Merge "Remove mateuszc@google.com from quickstep/tests/OWNERS" into main am: 2eadab3702 am: f18ee90f03

Original change: https://android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/3038502

Change-Id: I47a7f594de62981ca4252c524e218597002d29b0
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index 19d2a58..13a926b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -17,10 +17,12 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-min_launcher3_sdk_version = "26"
+min_launcher3_sdk_version = "30"
 
 // Common source files used to build launcher (java and kotlin)
 // All sources are split so they can be reused in many other libraries/apps in other folders
+
+// Main Launcher source, excluding the build config
 filegroup {
     name: "launcher-src",
     srcs: [
@@ -29,6 +31,7 @@
     ],
 }
 
+// Source code for quickstep build, on top of launcher-src
 filegroup {
     name: "launcher-quickstep-src",
     srcs: [
@@ -37,51 +40,20 @@
     ],
 }
 
+// Alternate source when quickstep is not included
 filegroup {
-    name: "launcher-go-src",
+    name: "launcher-src_no_quickstep",
     srcs: [
-        "go/src/**/*.java",
-        "go/src/**/*.kt",
+        "src_no_quickstep/**/*.java",
+        "src_no_quickstep/**/*.kt",
     ],
 }
 
+// Default build config for Launcher3
 filegroup {
-    name: "launcher-go-quickstep-src",
+    name: "launcher-build-config",
     srcs: [
-        "go/quickstep/src/**/*.java",
-        "go/quickstep/src/**/*.kt",
-    ],
-}
-
-filegroup {
-    name: "launcher-src_shortcuts_overrides",
-    srcs: [
-        "src_shortcuts_overrides/**/*.java",
-        "src_shortcuts_overrides/**/*.kt",
-    ],
-}
-
-filegroup {
-    name: "launcher-src_ui_overrides",
-    srcs: [
-        "src_ui_overrides/**/*.java",
-        "src_ui_overrides/**/*.kt",
-    ],
-}
-
-filegroup {
-    name: "launcher-ext_tests",
-    srcs: [
-        "ext_tests/**/*.java",
-        "ext_tests/**/*.kt",
-    ],
-}
-
-filegroup {
-    name: "launcher-quickstep-ext_tests",
-    srcs: [
-        "quickstep/ext_tests/**/*.java",
-        "quickstep/ext_tests/**/*.kt",
+        "src_build_config/**/*.java",
     ],
 }
 
@@ -103,18 +75,16 @@
         "androidx.test.uiautomator_uiautomator",
         "androidx.preference_preference",
         "SystemUISharedLib",
-        "animationlib",
+        "//frameworks/libs/systemui:animationlib",
         "launcher-testing-shared",
     ],
     srcs: [
         "tests/tapl/**/*.java",
+        "tests/tapl/**/*.kt",
     ],
     resource_dirs: [],
     manifest: "tests/tapl/AndroidManifest.xml",
     platform_apis: true,
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 }
 
 java_library_static {
@@ -132,9 +102,6 @@
         ],
     },
     static_libs: ["libprotobuf-java-lite"],
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 }
 
 java_library_static {
@@ -153,9 +120,6 @@
         "libprotobuf-java-lite",
         "launcher_log_protos_lite",
     ],
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 }
 
 java_library {
@@ -167,9 +131,6 @@
 
     sdk_version: "current",
     min_sdk_version: min_launcher3_sdk_version,
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 }
 
 // Library with all the dependencies for building Launcher3
@@ -180,6 +141,7 @@
     static_libs: [
         "LauncherPluginLib",
         "launcher_quickstep_log_protos_lite",
+        "android.os.flags-aconfig-java",
         "androidx-constraintlayout_constraintlayout",
         "androidx.recyclerview_recyclerview",
         "androidx.dynamicanimation_dynamicanimation",
@@ -187,38 +149,28 @@
         "androidx.preference_preference",
         "androidx.slice_slice-view",
         "androidx.cardview_cardview",
+        "androidx.window_window",
         "com.google.android.material_material",
-        "iconloader_base",
-        "view_capture",
-        "animationlib",
-    ],
-    manifest: "AndroidManifest-common.xml",
-    sdk_version: "current",
-    min_sdk_version: min_launcher3_sdk_version,
-    lint: {
-        baseline_filename: "lint-baseline-res-lib.xml",
-    },
-}
-
-//
-// Build rule for Launcher3 dependencies lib.
-//
-android_library {
-    name: "Launcher3CommonDepsLib",
-    srcs: ["src_build_config/**/*.java"],
-    static_libs: [
+        "//frameworks/libs/systemui:iconloader_base",
+        "//frameworks/libs/systemui:view_capture",
+        "//frameworks/libs/systemui:animationlib",
         "SystemUI-statsd",
-        "Launcher3ResLib",
         "launcher-testing-shared",
-        "animationlib",
+        "androidx.lifecycle_lifecycle-common-java8",
+        "androidx.lifecycle_lifecycle-extensions",
+        "androidx.lifecycle_lifecycle-runtime-ktx",
+        "kotlinx_coroutines_android",
+        "kotlinx_coroutines",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
+        "android.appwidget.flags-aconfig-java",
+        "com.android.window.flags.window-aconfig-java",
     ],
+    manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
     min_sdk_version: min_launcher3_sdk_version,
-    manifest: "AndroidManifest-common.xml",
     lint: {
-        baseline_filename: "lint-baseline-common-deps-lib.xml",
+        baseline_filename: "lint-baseline.xml",
     },
 }
 
@@ -229,17 +181,14 @@
     name: "Launcher3",
 
     static_libs: [
-        "Launcher3CommonDepsLib",
+        "Launcher3ResLib",
     ],
     srcs: [
         ":launcher-src",
-        ":launcher-src_shortcuts_overrides",
-        ":launcher-src_ui_overrides",
-        ":launcher-ext_tests",
+        ":launcher-src_no_quickstep",
+        ":launcher-build-config",
     ],
-    resource_dirs: [
-        "ext_tests/res",
-    ],
+
     optimize: {
         proguard_flags_files: ["proguard.flags"],
         // Proguard is disable for testing. Derivarive prjects to keep proguard enabled
@@ -265,7 +214,7 @@
         "AndroidManifest-common.xml",
     ],
     lint: {
-        baseline_filename: "lint-baseline-launcher3.xml",
+        baseline_filename: "lint-baseline.xml",
     },
 }
 
@@ -284,27 +233,21 @@
         "lottie",
         "SystemUISharedLib",
         "SettingsLibSettingsTheme",
-        "SystemUI-statsd",
-        "animationlib",
     ],
     manifest: "quickstep/AndroidManifest.xml",
     min_sdk_version: "current",
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 }
 
-// Library with all the dependencies for building Launcher Go
+// Library with all the source code and dependencies for building Launcher Go
 android_library {
-    name: "LauncherGoResLib",
+    name: "Launcher3GoLib",
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
-        ":launcher-go-src",
-        ":launcher-go-quickstep-src",
+        "go/quickstep/src/**/*.java",
+        "go/quickstep/src/**/*.kt",
     ],
     resource_dirs: [
-        "go/res",
         "go/quickstep/res",
     ],
     // Note the ordering here is important when it comes to resource
@@ -312,7 +255,6 @@
     // in QuickstepResLib to take precendece, so it should be the final
     // dependency. See b/205278434 for how this can go wrong.
     static_libs: [
-        "Launcher3CommonDepsLib",
         "QuickstepResLib",
         "androidx.room_room-runtime",
     ],
@@ -323,18 +265,17 @@
         "AndroidManifest-common.xml",
     ],
     min_sdk_version: "current",
-    lint: {
-        baseline_filename: "lint-baseline-go-res-lib.xml",
-    },
+    // TODO(b/319712088): re-enable use_resource_processor
+    use_resource_processor: false,
 }
 
-// Build rule for Quickstep library
+// Library with all the source code and dependencies for building Quickstep
 android_library {
     name: "Launcher3QuickStepLib",
     srcs: [
         ":launcher-src",
         ":launcher-quickstep-src",
-        ":launcher-src_shortcuts_overrides",
+        ":launcher-build-config",
     ],
     resource_dirs: [],
     libs: [
@@ -346,63 +287,13 @@
     // dependency. See b/208647810 for how this can go wrong.
     static_libs: [
         "SystemUI-statsd",
-        "SystemUISharedLib",
-        "Launcher3CommonDepsLib",
         "QuickstepResLib",
-        "animationlib",
     ],
     manifest: "quickstep/AndroidManifest.xml",
     platform_apis: true,
     min_sdk_version: "current",
-    lint: {
-        baseline_filename: "lint-baseline-launcher3.xml",
-    },
-}
-
-// Build rule for Launcher3 Go app for Android Go devices.
-android_app {
-    name: "Launcher3Go",
-
-    static_libs: ["Launcher3CommonDepsLib"],
-
-    srcs: [
-        ":launcher-src",
-        ":launcher-go-src",
-        ":launcher-src_ui_overrides",
-    ],
-
-    resource_dirs: ["go/res"],
-
-    optimize: {
-        proguard_flags_files: ["proguard.flags"],
-    },
-
-    sdk_version: "current",
-    min_sdk_version: "current",
-    target_sdk_version: "current",
-    privileged: true,
-    system_ext_specific: true,
-    overrides: [
-        "Home",
-        "Launcher2",
-        "Launcher3",
-        "Launcher3QuickStep",
-    ],
-    required: ["privapp_whitelist_com.android.launcher3"],
-
-    additional_manifests: [
-        "AndroidManifest.xml",
-        "AndroidManifest-common.xml",
-    ],
-
-    manifest: "go/AndroidManifest.xml",
-    jacoco: {
-        include_filter: ["com.android.launcher3.*"],
-    },
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
-
+    // TODO(b/319712088): re-enable use_resource_processor
+    use_resource_processor: false,
 }
 
 // Build rule for Quickstep app.
@@ -438,34 +329,23 @@
     jacoco: {
         include_filter: ["com.android.launcher3.*"],
     },
-    lint: {
-        baseline_filename: "lint-baseline.xml",
-    },
 
 }
 
-// Build rule for Launcher3 Go app with quickstep for Android Go devices.
-android_app {
-    name: "Launcher3QuickStepGo",
 
-    static_libs: [
-        "SystemUI-statsd",
-        "SystemUISharedLib",
-        "LauncherGoResLib",
-    ],
+// Build rule for Launcher3 Go app with quickstep for Android Go devices.
+// Note that the following two rules are exactly same, and should
+// eventually be merged into a single target
+android_app {
+    name: "Launcher3Go",
+
+    static_libs: ["Launcher3GoLib"],
+    resource_dirs: [],
 
     platform_apis: true,
     min_sdk_version: "current",
     target_sdk_version: "current",
 
-    srcs: [],
-
-    resource_dirs: [
-        "go/quickstep/res",
-        "go/res",
-        "quickstep/res",
-    ],
-
     optimize: {
         proguard_flags_files: ["proguard.flags"],
         enabled: true,
@@ -491,8 +371,40 @@
     jacoco: {
         include_filter: ["com.android.launcher3.*"],
     },
-    lint: {
-        baseline_filename: "lint-baseline.xml",
+}
+android_app {
+    name: "Launcher3QuickStepGo",
+
+    static_libs: ["Launcher3GoLib"],
+    resource_dirs: [],
+
+    platform_apis: true,
+    min_sdk_version: "current",
+    target_sdk_version: "current",
+
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+        enabled: true,
     },
 
+    privileged: true,
+    system_ext_specific: true,
+    overrides: [
+        "Home",
+        "Launcher2",
+        "Launcher3",
+        "Launcher3QuickStep",
+    ],
+    required: ["privapp_whitelist_com.android.launcher3"],
+
+    additional_manifests: [
+        "go/AndroidManifest.xml",
+        "go/AndroidManifest-launcher.xml",
+        "AndroidManifest-common.xml",
+    ],
+
+    manifest: "quickstep/AndroidManifest.xml",
+    jacoco: {
+        include_filter: ["com.android.launcher3.*"],
+    },
 }
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 7e824ec..edbea88 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -52,18 +52,18 @@
     name in the permissions. eq com.mypackage.permission.READ_SETTINGS
     -->
     <permission
-        android:name="${packageName}.permission.READ_SETTINGS"
+        android:name="${applicationId}.permission.READ_SETTINGS"
         android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_read_settings"
         android:description="@string/permdesc_read_settings"/>
     <permission
-        android:name="${packageName}.permission.WRITE_SETTINGS"
+        android:name="${applicationId}.permission.WRITE_SETTINGS"
         android:protectionLevel="signatureOrSystem"
         android:label="@string/permlab_write_settings"
         android:description="@string/permdesc_write_settings"/>
 
-    <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
-    <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="${applicationId}.permission.READ_SETTINGS" />
+    <uses-permission android:name="${applicationId}.permission.WRITE_SETTINGS" />
 
     <application
         android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -126,10 +126,10 @@
         -->
         <provider
             android:name="com.android.launcher3.LauncherProvider"
-            android:authorities="${packageName}.settings"
+            android:authorities="${applicationId}.settings"
             android:exported="true"
-            android:writePermission="${packageName}.permission.WRITE_SETTINGS"
-            android:readPermission="${packageName}.permission.READ_SETTINGS" />
+            android:writePermission="${applicationId}.permission.WRITE_SETTINGS"
+            android:readPermission="${applicationId}.permission.READ_SETTINGS" />
 
         <!--
         The content provider for exposing various launcher grid options.
@@ -137,7 +137,7 @@
         -->
         <provider
             android:name="com.android.launcher3.graphics.GridCustomizationsProvider"
-            android:authorities="${packageName}.grid_control"
+            android:authorities="${applicationId}.grid_control"
             android:exported="true" />
 
         <!--
@@ -157,7 +157,7 @@
 
         <provider
             android:name="com.android.launcher3.testing.TestInformationProvider"
-            android:authorities="${packageName}.TestInfo"
+            android:authorities="${applicationId}.TestInfo"
             android:readPermission="android.permission.WRITE_SECURE_SETTINGS"
             android:writePermission="android.permission.WRITE_SECURE_SETTINGS"
             android:exported="true"
@@ -184,5 +184,9 @@
             android:name="androidx.startup.InitializationProvider"
             android:authorities="${applicationId}.androidx-startup"
             tools:node="remove" />
+
+        <property
+            android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
+            android:value="true" />
     </application>
 </manifest>
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4f580e0..517bd6d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -20,7 +20,7 @@
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.launcher3">
-    <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="26"/>
+    <uses-sdk android:targetSdkVersion="33" android:minSdkVersion="30"/>
     <!--
     Manifest entries specific to Launcher3. This is merged with AndroidManifest-common.xml.
     Refer comments around specific entries on how to extend individual components.
diff --git a/OWNERS b/OWNERS
index 38963d0..654493f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,10 +10,8 @@
 vadimt@google.com
 winsonc@google.com
 jonmiranda@google.com
-alexchau@google.com
-patmanning@google.com
-tsuharesu@google.com
 awickham@google.com
+agvard@google.com
 
 # Launcher workspace eng team
 captaincole@google.com
@@ -26,5 +24,27 @@
 andonian@google.com
 sihua@google.com
 
+# Multitasking eng team
+tracyzhou@google.com
+peanutbutter@google.com
+jeremysim@google.com
+
+# Overview eng team
+alexchau@google.com
+samcackett@google.com
+silvajordan@google.com
+uwaisashraf@google.com
+
+# Physical Keyboard & Trackpad eng team
+patmanning@google.com
+helencheuk@google.com
+
+# Widget Picker team
+shamalip@google.com
+zakcohen@google.com
+
 per-file FeatureFlags.java, globs = set noparent
 per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com, captaincole@google.com
+
+per-file DeviceConfigWrapper.java, globs = set noparent
+per-file DeviceConfigWrapper.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index dc30a35..bca7494 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,6 +20,7 @@
 aconfig_declarations {
     name: "com_android_launcher3_flags",
     package: "com.android.launcher3",
+    container: "system_ext",
     srcs: ["**/*.aconfig"],
 }
 
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index af175ce..eced590 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.launcher3"
+container: "system_ext"
 
 flag {
     name: "enable_expanding_pause_work_button"
@@ -15,6 +16,13 @@
 }
 
 flag {
+    name: "enable_twoline_toggle"
+    namespace: "launcher"
+    description: "Enables visibility in home settings to see the toggle to turn on/off two lines in all apps."
+    bug: "316027081"
+}
+
+flag {
     name: "enable_grid_only_overview"
     namespace: "launcher"
     description: "Enable a grid-only overview without a focused task."
@@ -43,6 +51,13 @@
 }
 
 flag {
+    name: "enable_focus_outline"
+    namespace: "launcher"
+    description: "Enables focus states outline for launcher."
+    bug: "310953377"
+}
+
+flag {
     name: "enable_taskbar_no_recreate"
     namespace: "launcher"
     description: "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext."
@@ -60,21 +75,7 @@
     name: "enable_taskbar_pinning"
     namespace: "launcher"
     description: "Enables taskbar pinning to allow user to switch between transient and persistent taskbar flavors."
-    bug: "270396583"
-}
-
-flag {
-    name: "enable_split_from_fullscreen_with_keyboard_shortcuts"
-    namespace: "launcher"
-    description: "Enables initiating split from a fullscreen app using keyboard shortcuts"
-    bug: "270394122"
-}
-
-flag {
-    name: "enable_launcher_br_metrics"
-    namespace: "launcher"
-    description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
-    bug: "307527314"
+    bug: "296231746"
 }
 
 flag {
@@ -90,3 +91,158 @@
     description: "Enables full width two pane widget picker for tablets in landscape and portrait"
     bug: "315055849"
 }
+
+flag {
+    name: "enable_two_pane_launcher_settings"
+    namespace: "launcher"
+    description: "Enables two panel settings when on large enough displays"
+    bug: "204463748"
+}
+
+flag {
+    name: "enable_predictive_back_gesture"
+    namespace: "launcher"
+    description: "Enable predictive back gesture on Launcher (including all apps and widget picker)."
+    bug: "238475505"
+}
+
+flag {
+    name: "enable_shortcut_dont_suggest_app"
+    namespace: "launcher"
+    description: "Enables don't suggest app shortcut for suggested apps"
+    bug: "319250810"
+}
+
+flag {
+    name: "enable_support_for_archiving"
+    namespace: "launcher"
+    description: "Enables support for archived apps in Launcher3, such as empty progress bar etc."
+    bug: "210590852"
+}
+
+flag {
+    name: "enable_private_space_install_shortcut"
+    namespace: "launcher"
+    description: "Enables long-press shortcut to install a copy of an app to Private space"
+    bug: "316118005"
+}
+
+flag {
+    name: "enable_launcher_br_metrics_fixed"
+    namespace: "launcher"
+    description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
+    bug: "307527314"
+    is_fixed_read_only: true
+}
+
+flag {
+    name: "enable_reboot_unlock_animation"
+    namespace: "launcher"
+    description: "Enables unlock animation after device reboot"
+    bug: "298231234"
+}
+
+flag {
+    name: "enable_workspace_inflation"
+    namespace: "launcher"
+    description: "Enables asnc inflation of workspace icons"
+    bug: "318539160"
+}
+
+flag {
+    name: "enable_unfold_state_animation"
+    namespace: "launcher"
+    description: "Tie unfold animation with state animation"
+    bug: "297057373"
+}
+
+flag {
+    name: "enable_generated_previews"
+    namespace: "launcher"
+    description: "Enables support for RemoteViews previews in the widget picker."
+    bug: "306546610"
+}
+
+flag {
+  name: "enable_categorized_widget_suggestions"
+  namespace: "launcher"
+  description: "Enables widget suggestions in widget picker to be displayed in categories"
+  bug: "318410881"
+}
+
+flag {
+  name: "force_monochrome_app_icons"
+  namespace: "launcher"
+  description: "Enable the ability to generate monochromatic icons, if it is not provided by the app"
+  bug: "270396209"
+}
+
+flag {
+  name: "enable_add_app_widget_via_config_activity_v2"
+  namespace: "launcher"
+  description: "When adding app widget through config activity, directly add it to workspace to reduce flicker"
+  bug: "284236964"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+    name: "use_activity_overlay"
+    namespace: "launcher"
+    description: "Use an activity for home screen overlay"
+    bug: "273828110"
+}
+
+flag {
+    name: "enable_grid_migration_fix"
+    namespace: "launcher"
+    description: "Keep items in place when migrating to a bigger grid"
+    bug: "325286145"
+    is_fixed_read_only: true
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "enable_narrow_grid_restore"
+    namespace: "launcher"
+    description: "Using only the most recent workspace when restoring to avoid confusion."
+    is_fixed_read_only: true
+    bug: "325285743"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "enable_scaling_reveal_home_animation"
+    namespace: "launcher"
+    description: "Enables the Home gesture animation"
+    bug: "308801666"
+}
+
+flag {
+    name: "enable_widget_tap_to_add"
+    namespace: "launcher"
+    description: "Enables an add button in the widget picker"
+    bug: "323886237"
+}
+
+flag {
+  name: "enable_handle_delayed_gesture_callbacks"
+  namespace: "launcher"
+  description: "Enables additional handling for delayed mid-gesture callbacks"
+  bug: "285636175"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
+    name: "enable_fallback_overview_in_window"
+    namespace: "launcher"
+    description: "Enables fallback recents opening inside of a window instead of an activity."
+    bug: "292269949"
+}
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index fc79200..31d8d34 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.launcher3"
+container: "system_ext"
 
 flag {
     name: "enable_private_space"
@@ -12,4 +13,32 @@
     namespace: "launcher_search"
     description: "This flag enables the animation of the Private Space container"
     bug: "299294792"
-}
\ No newline at end of file
+}
+
+flag {
+    name: "private_space_sys_apps_separation"
+    namespace: "launcher_search"
+    description: "This flag enables showing system apps separate in Private Space container."
+    bug: "308054233"
+}
+
+flag {
+    name: "private_space_app_installer_button"
+    namespace: "launcher_search"
+    description: "This flag enables addition of App Installer button in Private Space container."
+    bug: "308064949"
+}
+
+flag {
+    name: "private_space_restrict_accessibility_drag"
+    namespace: "launcher_search"
+    description: "This flag disables accessibility drag for Private Space Apps."
+    bug: "289223923"
+}
+
+flag {
+    name: "private_space_restrict_item_drag"
+    namespace: "launcher_search"
+    description: "This flag disables drag and drop for Private Space Items."
+    bug: "289223923"
+}
diff --git a/buglist.txt b/buglist.txt
deleted file mode 100644
index 53dcc35..0000000
--- a/buglist.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-171450807
-170675311
-170338029
-170338170
-160544577
-171171594
-170488559
-171131394
-171131394
-171026321
-170648272
-170752716
-170611866
-170702596
-170487752
-170665892
-168608912
-170636685
-169771796
-141126144
-166614700
-168805872
-170263425
-169221288
-143965596
-169221287
-167259591
-156044202
-169438169
-164926736
-168653219
-169963211
-170121063
-169988381
-169980192
-169221288
-169385783
-168167693
-169796517
-169330678
-168818961
-168608912
diff --git a/buglist_unique.txt b/buglist_unique.txt
deleted file mode 100644
index 93dbefb..0000000
--- a/buglist_unique.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-141126144
-143965596
-156044202
-160544577
-164926736
-166614700
-167259591
-168167693
-168608912
-168653219
-168805872
-168818961
-169221287
-169221288
-169330678
-169385783
-169438169
-169771796
-169796517
-169963211
-169980192
-169988381
-170121063
-170263425
-170338029
-170338170
-170487752
-170488559
-170611866
-170636685
-170648272
-170665892
-170675311
-170702596
-170752716
-171026321
-171131394
-171171594
-171450807
diff --git a/build.gradle b/build.gradle
deleted file mode 100644
index f4d7261..0000000
--- a/build.gradle
+++ /dev/null
@@ -1,188 +0,0 @@
-buildscript {
-    repositories {
-        mavenCentral()
-        google()
-    }
-    dependencies {
-        classpath GRADLE_CLASS_PATH
-        classpath PROTOBUF_CLASS_PATH
-    }
-}
-
-final String ANDROID_TOP = "${rootDir}/../../.."
-final String FRAMEWORK_PREBUILTS_DIR = "${ANDROID_TOP}/prebuilts/framework_intermediates/"
-
-apply plugin: 'com.android.application'
-apply plugin: 'com.google.protobuf'
-
-android {
-    compileSdkVersion COMPILE_SDK
-    buildToolsVersion BUILD_TOOLS_VERSION
-
-    defaultConfig {
-        minSdkVersion 26
-        targetSdkVersion 30
-        versionCode 1
-        versionName "1.0"
-
-        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-        vectorDrawables.useSupportLibrary = true
-    }
-    buildTypes {
-        debug {
-            minifyEnabled false
-        }
-    }
-
-    compileOptions {
-        sourceCompatibility JavaVersion.VERSION_1_8
-        targetCompatibility JavaVersion.VERSION_1_8
-    }
-
-    // The flavor dimensions for build variants (e.g. aospWithQuickstep, aospWithoutQuickstep)
-    // See: https://developer.android.com/studio/build/build-variants#flavor-dimensions
-    flavorDimensions "app", "recents"
-
-    productFlavors {
-        aosp {
-            dimension "app"
-            applicationId 'com.android.launcher3'
-            testApplicationId 'com.android.launcher3.tests'
-        }
-
-        l3go {
-            dimension "app"
-            applicationId 'com.android.launcher3'
-            testApplicationId 'com.android.launcher3.tests'
-        }
-
-        withQuickstep {
-            dimension "recents"
-
-            minSdkVersion 28
-        }
-
-        withoutQuickstep {
-            dimension "recents"
-        }
-    }
-
-    // Disable release builds for now
-    android.variantFilter { variant ->
-        if (variant.buildType.name.endsWith('release')) {
-            variant.setIgnore(true)
-        }
-    }
-
-    sourceSets {
-        main {
-            res.srcDirs = ['res']
-            java.srcDirs = ['src', 'src_plugins']
-            manifest.srcFile 'AndroidManifest-common.xml'
-            proto {
-                srcDirs = ['protos/', 'protos_overrides/']
-            }
-        }
-
-        androidTest {
-            res.srcDirs = ['tests/res']
-            java.srcDirs = ['tests/src', 'tests/tapl']
-            manifest.srcFile "tests/AndroidManifest-common.xml"
-        }
-
-        androidTestDebug {
-            manifest.srcFile "tests/AndroidManifest.xml"
-        }
-
-        aosp {
-            java.srcDirs = ['src_flags', 'src_shortcuts_overrides']
-        }
-
-        aospWithoutQuickstep {
-            manifest.srcFile "AndroidManifest.xml"
-        }
-
-        aospWithQuickstep {
-            manifest.srcFile "quickstep/AndroidManifest-launcher.xml"
-        }
-
-        l3go {
-            res.srcDirs = ['go/res']
-            java.srcDirs = ['go/src']
-            manifest.srcFile "go/AndroidManifest.xml"
-        }
-
-        l3goWithoutQuickstepDebug {
-            manifest.srcFile "AndroidManifest.xml"
-        }
-
-        l3goWithQuickstepDebug {
-            manifest.srcFile "quickstep/AndroidManifest-launcher.xml"
-        }
-
-        withoutQuickstep {
-            java.srcDirs = ['src_ui_overrides']
-        }
-
-        withQuickstep {
-            res.srcDirs = ['quickstep/res', 'quickstep/recents_ui_overrides/res']
-            java.srcDirs = ['quickstep/src', 'quickstep/recents_ui_overrides/src']
-            manifest.srcFile "quickstep/AndroidManifest.xml"
-        }
-    }
-}
-
-allprojects {
-    repositories {
-        maven { url "../../../prebuilts/sdk/current/androidx/m2repository" }
-        maven { url "../../../prebuilts/fullsdk-darwin/extras/android/m2repository" }
-        maven { url "../../../prebuilts/fullsdk-linux/extras/android/m2repository" }
-        mavenCentral()
-        google()
-    }
-}
-
-dependencies {
-    implementation "androidx.dynamicanimation:dynamicanimation:${ANDROID_X_VERSION}"
-    implementation "androidx.recyclerview:recyclerview:${ANDROID_X_VERSION}"
-    implementation "androidx.preference:preference:${ANDROID_X_VERSION}"
-    implementation project(':IconLoader')
-    implementation project(':UiTestsLibLauncher')
-    withQuickstepImplementation project(':SharedLibWrapper')
-
-    // Recents lib dependency
-    withQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/quickstep/libs", include: 'sysui_shared.jar')
-
-    // Required for AOSP to compile. This is already included in the sysui_shared.jar
-    withoutQuickstepImplementation fileTree(dir: "${FRAMEWORK_PREBUILTS_DIR}/libs", include: 'plugin_core.jar')
-
-    testImplementation 'junit:junit:4.12'
-    testImplementation libs.mockitoInlineExtended
-    androidTestImplementation libs.mockitoInlineExtended
-    androidTestImplementation "org.mockito:mockito-core:1.9.5"
-    androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
-    androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
-    androidTestImplementation 'com.android.support.test:runner:1.0.0'
-    androidTestImplementation 'com.android.support.test:rules:1.0.0'
-    androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
-    androidTestImplementation "androidx.annotation:annotation:${ANDROID_X_VERSION}"
-
-    api 'com.airbnb.android:lottie:3.3.0'
-}
-
-protobuf {
-    // Configure the protoc executable
-    protoc {
-        artifact = "com.google.protobuf:protoc:${protocVersion}${PROTO_ARCH_SUFFIX}"
-    }
-    generateProtoTasks {
-        all().each { task ->
-            task.builtins {
-                remove java
-                java {
-                    option "lite"
-                }
-            }
-        }
-    }
-}
diff --git a/commitlist.txt b/commitlist.txt
deleted file mode 100644
index 27b8bac..0000000
--- a/commitlist.txt
+++ /dev/null
@@ -1,934 +0,0 @@
-COMMAND>> git log f99351888c3e5a128559678304fefd647472bc7f..4c3952dc60fc78d3816012a86d7e71747ef34c74
-commit 4c3952dc60fc78d3816012a86d7e71747ef34c74
-Merge: cb403d9e5 70e8b1572
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Fri Oct 23 00:27:39 2020 +0000
-
-    Merge "Minor stylistic changes in Workspace.java." into ub-launcher3-master
-
-commit cb403d9e5235c7323bc2fdffe6a264d17bb6d0a6
-Author: Pinyao Ting <pinyaoting@google.com>
-Date:   Thu Oct 22 16:07:08 2020 -0700
-
-    flip default value of minimal device feature flag
-    
-    Test: manual
-    Change-Id: Iaf46dffb935bdf4b46e7c57d547bdc697250ec56
-
-commit a97557a15eb111616d868120a9f4659f1b451fa2
-Merge: f5ce80b8a 932a327eb
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Thu Oct 22 18:22:56 2020 +0000
-
-    Merge "Consider overscroll adjustment of RecentsView for live tile" into ub-launcher3-master
-
-commit 932a327ebf0587b8324b9fea7d31328b2f6719a8
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 21 23:29:00 2020 -0700
-
-    Consider overscroll adjustment of RecentsView for live tile
-    
-    Fixes: 171450807
-    Test: manual
-    Change-Id: I83eebf1f6b61c67f289db51aabe5a971815d0df1
-
-commit f5ce80b8a0a1636fc8159475177a07b281492c88
-Author: Hilary Huo <hhuo@google.com>
-Date:   Wed Oct 14 16:35:55 2020 -0700
-
-    [pixel-search] Latency analysis, add logging statement in launcher
-    
-    Bug: b/170675311
-    Change-Id: I229ace399085bea1c3f9535eb713edd329dff8bd
-
-commit 31b03941ef3aa17edc08c1b509d4fa23766f2d2c
-Merge: e0a50c9e3 0731273d5
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 21 20:03:57 2020 +0000
-
-    Merge "Track live tile better by considering resistance animation" into ub-launcher3-master
-
-commit 0731273d5409149fca32dfb2ad76eab45f6ea79a
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 21 12:03:40 2020 -0700
-
-    Track live tile better by considering resistance animation
-    
-    Fixes: 170338029
-    Test: Manual
-    Change-Id: I66536bae567aa94385d5e0352cec9d46d512927a
-
-commit e0a50c9e3f1d4b9f113d6afae01ff2c4ed452fba
-Merge: d2c27a595 acfac6187
-Author: Alex Chau <alexchau@google.com>
-Date:   Wed Oct 21 17:02:57 2020 +0000
-
-    Merge "Use Diplay.getMetrics in DisplayController" into ub-launcher3-master
-
-commit d2c27a595065d43bbea37dd2a512d37080f5233e
-Merge: ff8febabb 8b488ccc2
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 21 07:19:48 2020 +0000
-
-    Merge "[Live Tile] Support launching running task animation" into ub-launcher3-master
-
-commit 8b488ccc2e433a708c8b06f0b6866f2a305e4b0a
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 14 12:13:04 2020 -0700
-
-    [Live Tile] Support launching running task animation
-    
-    Fixes: 170338170
-    Test: manual
-    Change-Id: I2526b7cfbacaea7899b8e2ed233f913630071d36
-
-commit 70e8b157219e9090ba5e47fdfa51b2b92e98449d
-Author: Andy Wickham <awickham@google.com>
-Date:   Wed Oct 7 23:00:06 2020 -0700
-
-    Minor stylistic changes in Workspace.java.
-    
-    Change-Id: Ib07611f27cbc427d11abccd8b74ea144485752f7
-
-commit acfac6187dd9d13d55b566a77a5da867a1813573
-Author: Alex Chau <alexchau@google.com>
-Date:   Mon Oct 19 18:00:39 2020 +0100
-
-    Use Diplay.getMetrics in DisplayController
-    
-    - This is a workaround of b/163815566, where DisplayMetrics is stale
-      when onDisplayChanged is called.
-    - Instead of relying on stale DisplayConext, get the DisplayMetrics
-      from the Display directly.
-    - Also optimized how DisplayController.Info is created by passing in
-      Display only
-    - Use mDisplayContext.getDisplay directly if availalbe
-    
-    Bug: 163815566, 160544577
-    Test: DPI looks correct on device boot
-    Change-Id: I2a7454bb8cf2073ce592e8662781b87fc998444f
-    (cherry picked from commit 177c38243dc3bf245d1f7db3c265dfb56522f441)
-
-commit ff8febabb039a3c27ee068f85119860a048b917c
-Merge: b03d2b416 102746823
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Tue Oct 20 17:46:09 2020 +0000
-
-    Merge "Makes Plugin Settings gear adjust to dark mode." into ub-launcher3-master
-
-commit b03d2b41616d479ba360fa4f97e57722c7f57b8e
-Merge: fb79f5541 caa1e9c39
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Tue Oct 20 15:25:56 2020 +0000
-
-    Merge "Search query method should support multiple consumers" into ub-launcher3-master
-
-commit fb79f5541dcbe587002756bb40a3c632d38cc25a
-Merge: f6b05068d cf0b275a4
-Author: Schneider Victor-tulias <victortulias@google.com>
-Date:   Tue Oct 20 13:51:06 2020 +0000
-
-    Merge "Add the ability to specify a list of tutorial steps in the gesture sandbox tutorial intent." into ub-launcher3-master
-
-commit f6b05068d901d4e989b2e107c06f9c7a6e7b113f
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Tue Oct 20 00:19:29 2020 -0700
-
-    Invert the badging
-    
-    Bug: 171171594
-    Change-Id: If84fdc03254105c843e16f39f479505b16e1cd5f
-
-commit caa1e9c39978cb3b467b5ac441eb39b5e883fa2e
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Mon Oct 12 13:56:02 2020 -0700
-
-    Search query method should support multiple consumers
-    
-    Bug: 170488559
-    Change-Id: I64bef9523d3c3950c4ca3a4b9ce1d506d1672200
-
-commit 10274682339bb60cb24c50536b4f48f921970f3c
-Author: Andy Wickham <awickham@google.com>
-Date:   Mon Oct 19 19:06:52 2020 -0700
-
-    Makes Plugin Settings gear adjust to dark mode.
-    
-    It wasn't visible in dark mode before because it was
-    black on black. This makes it adjust automatically.
-    
-    Change-Id: I5176cffc01842509ddafc4f30ff5029a0c4b8050
-
-commit 744a0fbeae8efaa942d21c61e25012d86f5ff81e
-Merge: 29c79947e 71f24588c
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 19 22:17:26 2020 +0000
-
-    Merge "Call click event on IME quick select for SearchResultIcon" into ub-launcher3-master
-
-commit 29c79947ecf82f662d02004ba9a7289017fc0783
-Merge: 13a2a010d a68ac3e5d
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 19 18:42:05 2020 +0000
-
-    Merge "Removing condition for CUJ tracing/metrics" into ub-launcher3-master
-
-commit 71f24588c0a66449a0c68bcb360a8c671914ce75
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Mon Oct 19 10:19:31 2020 -0700
-
-    Call click event on IME quick select for SearchResultIcon
-    
-    Bug: 171131394
-    Change-Id: I8a703e8d0ca10570e3f774510610d3fb4c0eaab8
-
-commit 13a2a010decd87eeaf8932430c692f587d2de165
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Sun Oct 18 21:19:57 2020 -0700
-
-    Handle IME event for SearchResultIcon
-    
-    Bug: 171131394
-    Test: Manual
-    Change-Id: I2ed1c61053c78aaecc3324418229d69634a72ae4
-
-commit 1f79eeda76246534697e92740defc7f73c3c8d14
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Fri Oct 16 02:01:31 2020 -0700
-
-    Remove hardcoded itemTypes from SearchTarget
-    
-    - Introduces componentName and userHandle members to SearchTarget
-    - SearchTargetEvent now has searchTarget member
-    - Builder pattern for SearchTarget and SearchTargetEvent
-    - Search backend should add headers manually instead of launcher inferring sections
-    
-    Bug: 171026321
-    Test: Manual
-    Change-Id: I28e0455e82b925277a17703b9aa061c8f9f15262
-
-commit a68ac3e5dd23095cea7c872c0ff1c5042d1695ba
-Author: vadimt <vadimt@google.com>
-Date:   Fri Oct 16 10:48:28 2020 -0700
-
-    Removing condition for CUJ tracing/metrics
-    
-    Is doesn't reflect whether jank monitors is collecting metrics,
-    which will eventually be always true anyways.
-    
-    Change-Id: Iaebdc838ed2b2cebd32c8c48d7e45bdd93f76fb4
-
-commit 9228ff53c2fb26850b7bd92d86214a6aaebb11d3
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Mon Oct 12 13:43:51 2020 -0700
-
-    Trimming activity and task label
-    
-    Bug: 170648272
-    Change-Id: Icd099acee65305e0aa0f98a2a301a0df8a27cf07
-
-commit 7a09177e500a53205f9969bb6cbd4251d54e8fde
-Merge: 37ed5ead3 314761a80
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Thu Oct 15 22:36:14 2020 +0000
-
-    Merge "Setup SearchResultIcon for single cell results" into ub-launcher3-master
-
-commit 37ed5ead391df5747003b2d3a345be0347362f19
-Merge: d5bbe6809 702ed2788
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Thu Oct 15 22:06:12 2020 +0000
-
-    Merge "Fix the issue where shortcuts are removed in minimal device mode" into ub-launcher3-master
-
-commit 314761a80819a6e64a136161f51eebb0f0528c4d
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Wed Oct 14 10:15:07 2020 -0700
-
-    Setup SearchResultIcon for single cell results
-    
-    SearchResultIcon will be able to render apps, shortcuts and remote actions. It can also handle its own focused state drawing.
-    
-    Screenshot: https://screenshot.googleplex.com/C3KgjJtLQTBPgaf
-    
-    Bug: 170752716
-    Test: Manual
-    Change-Id: I460a9c128ea3f5814784e342c5d5fa5b7e310882
-
-commit 702ed2788678ac744c768aad6a6302e7cf91a26b
-Author: Pinyao Ting <pinyaoting@google.com>
-Date:   Wed Oct 14 11:17:04 2020 -0700
-
-    Fix the issue where shortcuts are removed in minimal device mode
-    
-    When loading the workspace, Launcher pins/unpins shortcuts in comply
-    with the loaded workspace. Since minimal device mode creates a mostly
-    empty workspace, existing shortcuts are getting unpinned as a result.
-    
-    To mitigate the issue this CL compares the db name and only invoke
-    sanitizeData when it matches the one defined in InvariantDeviceProfile.
-    
-    Bug: 170611866
-    Test: manual
-    1. add some deep shortcut in workspace (e.g. long tap on chrome, drag
-    "incognito tab" to workspace)
-    2. opt-in to sunshine fishfood (g/sunshine-teamfood)
-    3. enable bedtime mode with minimal device in Settings -> Digital
-    Wellbeing -> Show Your Data -> Bedtime mode -> Customize -> minimal
-    device
-    4. toggle bedtime mode, wait for apps in minimal device to show, then
-    toggle off bedtime mode
-    5. verify the deep shortcut still exist
-    
-    Change-Id: Ie18216ecb288e7481aa2404c4cb3ea418aee85cb
-
-commit cf0b275a48d3c9f91a346f7fc24b9604f6dde25a
-Author: Schneider Victor-tulias <victortulias@google.com>
-Date:   Tue Oct 6 09:33:40 2020 -0400
-
-    Add the ability to specify a list of tutorial steps in the gesture sandbox tutorial intent.
-    
-    Added tutorial_steps string array in the intent to allow specifying an ordered list of tutorial steps.
-    
-    Change-Id: Ic42a65598a74a64f8441a22f58c6cd988a5762e3
-
-commit d5bbe6809dcc056fbfc307909b171651f0fb3044
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Wed Oct 14 15:39:38 2020 -0700
-
-    Rename shrotcut container to deep-shrotcuts
-    
-    Change-Id: If94f0dfa447235f3b1a652f7b6c749695b42d97c
-
-commit 26c1105fa04c2bcc156051e51df90a6a253349bb
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Tue Oct 13 01:12:03 2020 -0700
-
-    [search api part 1] Setup centralized SearchEventTracker
-    
-    - Rename AdapterItemWIthPayload to SearchAdapterItem, PayloadResultHandler to SearchTargetHandler
-    - Setup SliceViewWrapper for self contained slices
-    
-    Bug: 170702596
-    Change-Id: I0baf984ec8123c95011abcc17372f8d055e98ad7
-
-commit 057f2d0d7df67e3680e479ac76b48b30d8bcf884
-Merge: 4bb65ff51 9a6145efb
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Tue Oct 13 01:57:47 2020 +0000
-
-    Merge "Introduce shortcut container for hotseat event reporting" into ub-launcher3-master
-
-commit 4bb65ff516c6d9a429971ab7e04780792d5cb751
-Merge: 69740e62b 2afcab804
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Tue Oct 13 00:07:36 2020 +0000
-
-    Merge "Search UI clean up" into ub-launcher3-master
-
-commit 2afcab804b638ff3b9da5bad40c8f70bdcaae78d
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Mon Oct 12 15:38:14 2020 -0700
-
-    Search UI clean up
-    
-    - Resolve spacing issue when work profile is installed
-    - Cache play icons and use icon shape
-    - Only draw focus indicator for the first result
-    
-    Bug: 170487752
-    Bug: 170665892
-    Change-Id: I864d2e796786637132e127ef9b418c0a76c74d6e
-
-commit 69740e62be3800fc918648009645f7a8e52cb73d
-Merge: 2d7bfc878 979da64d8
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 12 20:53:29 2020 +0000
-
-    Merge "Add app start source info of apps launched from launcher" into ub-launcher3-master
-
-commit 2d7bfc8782e9ed01178672aeb09ba2a6a07f4f4c
-Author: Jon Miranda <jonmiranda@google.com>
-Date:   Mon Oct 12 12:09:22 2020 -0700
-
-    Fix shadowRadius not being used in swipe up animation.
-    
-    Bug: 168608912
-    Change-Id: I08f7bb057237e5061d5f1fc29afb488b204ee385
-
-commit a433fe1fb34715efb38ed094f39da49fce8cd51e
-Merge: 2de606fe7 0471b9836
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Mon Oct 12 18:08:35 2020 +0000
-
-    Merge "Using FrameCallbacks instead of windowCallbacks for surface removal" into ub-launcher3-master
-
-commit 9a6145efb85f2bbdaccc07166a55e22c15fe27db
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Mon Oct 12 09:33:00 2020 -0700
-
-    Introduce shortcut container for hotseat event reporting
-    
-    Bug: 170636685
-    Test: Manual
-    Change-Id: I5abeb17976bbafdc8cc74fb8b9a586d544c682fc
-
-commit 2de606fe731573c081fd2d6ba166e21ea6aa2e9c
-Author: Yogisha Dixit <ydixit@google.com>
-Date:   Mon Oct 12 15:36:07 2020 +0100
-
-    Delete the minimal database to force refresh.
-    
-    Bug: 169771796
-    Test: manual
-    Change-Id: Ic2188bb162f295c208346861fddc137ace19ddcb
-
-commit 0471b9836c9e382dc14bdc3abdf8502fb2b9f266
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Wed Sep 23 13:54:37 2020 -0700
-
-    Using FrameCallbacks instead of windowCallbacks for surface removal
-    
-    WindowCallbacks is called during the draw pass, before the frame has
-    been sent to the surfaceFlinger. Frame callback will provide a closer
-    approximation for when the frame is actually rendered on screen.
-    
-    Bug: 141126144
-    Change-Id: I62aab526c2ca24b00b5e7b312b36080f26c7b439
-
-commit 2727434c44d06882925369bf4b43687a06be4a3f
-Merge: 59f532fe9 1b9e199b3
-Author: Schneider Victor-tulias <victortulias@google.com>
-Date:   Fri Oct 9 20:09:08 2020 +0000
-
-    Merge "Fix hotseat and prediction row to allow updates when empty." into ub-launcher3-master
-
-commit 59f532fe9e2b1817c094641f3c7c517f42e4faf0
-Merge: d2bfce71f b5334e3f0
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Fri Oct 9 19:52:54 2020 +0000
-
-    Merge "Improve search section header" into ub-launcher3-master
-
-commit 979da64d8254599c332d83bf94f3f1fc3fe45fef
-Author: Riddle Hsu <riddlehsu@google.com>
-Date:   Tue Sep 22 21:52:40 2020 +0800
-
-    Add app start source info of apps launched from launcher
-    
-    Bug: 166614700
-    Test: Enable statsd log: "adb shell cmd stats print-logs"
-          adb logcat | grep statsd | grep "(48)"
-          The line may contain 0x100000->1[I] 0x110000->10[I]
-          that means 1=from launcher and 10=latency 10ms.
-    Change-Id: Iddaff7066b66e241ba58ec87129ddbe2c531dc7e
-    (cherry picked from commit 7bdf3574a3bff06a377b4364877687bfa7619d06)
-
-commit d2bfce71f776fd05633dfd915dfc664309274677
-Merge: ed4530fed 222afb970
-Author: Winson Chung <winsonc@google.com>
-Date:   Fri Oct 9 16:39:06 2020 +0000
-
-    Merge "Comply with the ISystemUiProxy.aidl change" into ub-launcher3-master
-
-commit ed4530fedda0bf876f91d0745fc70d0f30d42991
-Merge: 692d2109a 9d4a96ed0
-Author: Winson Chung <winsonc@google.com>
-Date:   Fri Oct 9 16:39:06 2020 +0000
-
-    Merge "Add latency metrics for recents gesture" into ub-launcher3-master
-
-commit 1b9e199b3d9c81c793758d96bb03e0c51c1b3fb1
-Author: Schneider Victor-tulias <victortulias@google.com>
-Date:   Thu Oct 8 15:50:22 2020 -0400
-
-    Fix hotseat and prediction row to allow updates when empty.
-    
-    Rotating the screen in the homescreen empties the hotseat, however it does not get populated while it is visible to the user. The user should not be able to see an empty hotseat or prediction row if predictions are available. It should therefore be possible to populate these when they are empty even if they are visible to the user.
-    
-    Change-Id: I8e5252bd29050c2cd9d443aedcb3f3e305c0e2d7
-
-commit b5334e3f07f0561808a2d6e9bba55f1e3a89191e
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Fri Oct 9 00:50:48 2020 -0700
-
-    Improve search section header
-    
-    Change-Id: I47cf207f0d0ab792c0e7a47c9d1185eec087ec88
-
-commit 692d2109a6702706d24b3b819d115882f7362509
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Thu Oct 8 18:42:48 2020 -0700
-
-    invalidate itemDecoration on predictedRow focus draw
-    
-    Change-Id: I66c731f00ae1c1292c51ff281957f05fd2d70dfa
-
-commit 8d5b118060bff7f7518a9a14c0be5d265621f14c
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Thu Oct 8 13:11:25 2020 -0700
-
-    Revert PredictionRow shuoldDraw check
-    
-    + Show Rounded play result icons
-    
-    Bug: 168805872
-    Test: Manual
-    Change-Id: I663c7f7ca1f1ac072e5e9c441deabef7c3fbd97b
-
-commit 86f8df6cf954ac27ab092b9ef8a4db3c9979c4cb
-Merge: 4d19854b2 16045060c
-Author: Hilary Huo <hhuo@google.com>
-Date:   Thu Oct 8 18:43:51 2020 +0000
-
-    Merge "[pixel-search] add escape hatch" into ub-launcher3-master
-
-commit 4d19854b25a54599fe9b0ac8be9d60cf6c21d7ba
-Merge: 0827e1e32 ab9ad20be
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Thu Oct 8 18:40:56 2020 +0000
-
-    Merge "Search UI cleanup" into ub-launcher3-master
-
-commit 16045060c35639aea85afc572bea768d16e6c9f9
-Author: Hilary Huo <hhuo@google.com>
-Date:   Thu Oct 8 10:18:41 2020 -0700
-
-    [pixel-search] add escape hatch
-    
-    Change-Id: I33ffea1fc0859564955380d7d1db317293d1a2cb
-
-commit 0827e1e32a5f99fa02418dae37270c6db8c989d2
-Merge: 3463f0a87 68d7a6e5b
-Author: Andy Wickham <awickham@google.com>
-Date:   Thu Oct 8 16:53:29 2020 +0000
-
-    Merge "Adds feature flag for BC Smartspace." into ub-launcher3-master
-
-commit ab9ad20be600d1cbdc6b54a491d5fbb4c2cf9c16
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Wed Oct 7 15:18:24 2020 -0700
-
-    Search UI cleanup
-    
-    - offset all apps header padding with search input margin
-    - avoid check shouldDraw check on HeaderRow. (race condition)
-    
-    Bug: 170263425
-    Change-Id: I11a1fbb448aa6afd18ec0984af9bb8b1d7600f69
-
-commit 68d7a6e5b28af8cc55bdae7efc24cc7ebee81257
-Author: Andy Wickham <awickham@google.com>
-Date:   Wed Oct 7 14:27:17 2020 -0700
-
-    Adds feature flag for BC Smartspace.
-    
-    Change-Id: Iaf9fb7507d0ccd004a4e00188c75dadd6a059246
-
-commit 3463f0a876ff486ce03e160134e0504158271a92
-Merge: 2470d812a 4b7f38b8f
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Wed Oct 7 20:09:04 2020 +0000
-
-    Merge "Align fallback result query with result text" into ub-launcher3-master
-
-commit 2470d812a1ae989e67781e5056b534ad9a960819
-Merge: cae7d74d8 7a6e4c931
-Author: Vadim Tryshev <vadimt@google.com>
-Date:   Wed Oct 7 20:04:09 2020 +0000
-
-    Merge "Annotating Quick Switch CUJ for 3-button mode" into ub-launcher3-master
-
-commit cae7d74d898769727105850ea5473c2c0ae25fdb
-Merge: e9bf2bd14 1fddddb4f
-Author: Tony Wickham <twickham@google.com>
-Date:   Wed Oct 7 18:32:48 2020 +0000
-
-    Merge "Update launcher_trace.proto for quick switch" into ub-launcher3-master
-
-commit 7a6e4c931f13b369bfa4328196b4632d6d848a19
-Author: vadimt <vadimt@google.com>
-Date:   Tue Oct 6 14:09:16 2020 -0700
-
-    Annotating Quick Switch CUJ for 3-button mode
-    
-    Bug: 169221288
-    Change-Id: Ief62345fe6004dde699f44aa0c90329b7cd84e8b
-
-commit 4b7f38b8fa004b514244304fcc07ff514a2fa46b
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Tue Oct 6 18:37:46 2020 -0700
-
-    Align fallback result query with result text
-    
-    screenshot: https://screenshot.googleplex.com/6Daj5vdmz2jmznX
-    bug: 169438169
-    test: Manual
-    Change-Id: Ie621ed3c834aec5e9467607da4f685d05d152183
-
-commit 222afb970434c7972589adfc509bd2c256ca6556
-Author: Hongwei Wang <hwwang@google.com>
-Date:   Fri Oct 2 13:51:36 2020 -0700
-
-    Comply with the ISystemUiProxy.aidl change
-    
-    Two methods are added to support communications between Launcher and
-    SysUI when user swipes an auto PiP-able Activity to home.
-    
-    Bug: 143965596
-    Test: N/A
-    Change-Id: I2c73a287a094e882bde3cd71c27f9f66ae20e64a
-    (cherry picked from commit 88ddae38db924f700082a113670ce5a719116a95)
-
-commit 9d4a96ed029fdad1e369d5eedd082938f0dc9e01
-Author: Riddle Hsu <riddlehsu@google.com>
-Date:   Wed Sep 30 00:32:04 2020 +0800
-
-    Add latency metrics for recents gesture
-    
-    Pass the touch down time to RecentsAnimation#startRecentsActivity.
-    
-    Bug: 169221287
-    Test: Enable statsd log: "adb shell cmd stats print-logs"
-          Touch gesture navigation bar.
-          adb logcat | grep statsd | grep "(48)"
-          The line may contain 0x100000->4[I] 0x110000->20[I]
-          that means 4=by recents and 20=latency 20ms.
-    Change-Id: I81ee804895b7712f4d925736f5b4694c11a12cbe
-    (cherry picked from commit 63623967b83edad56db58173ebb6687c685b9177)
-
-commit e9bf2bd14c9a7a48f8f93687932d41b1418cf4e4
-Merge: 73ae75474 d028937e7
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Wed Oct 7 02:19:04 2020 +0000
-
-    Merge "[Live tile] Finish recents animation when the phone goes to sleep in live tile mode" into ub-launcher3-master
-
-commit 1fddddb4f30505e0fc9bb2e7c0d88b38ad900e54
-Author: Tony Wickham <twickham@google.com>
-Date:   Tue Sep 29 17:29:06 2020 -0700
-
-    Update launcher_trace.proto for quick switch
-    
-    Sample output from one entry:
-    entry {
-      elapsed_realtime_nanos: 440461382888540
-      launcher {
-        touch_interaction_service {
-          service_connected: true
-          overview_component_obvserver {
-            overview_activity_started: true
-            overview_activity_resumed: false
-          }
-          input_consumer {
-            name: "TYPE_OTHER_ACTIVITY:TYPE_ONE_HANDED"
-            swipe_handler {
-              gesture_state {
-                endTarget: NEW_TASK
-              }
-              is_recents_attached_to_app_window: true
-              scroll_offset: 846
-              app_to_overview_progress: 0
-            }
-          }
-        }
-      }
-    }
-    
-    Bug: 167259591
-    Change-Id: I7f199d88f1d736efcea6b9165b8c4b77a5d27c58
-
-commit 73ae75474ec1dd8807d814ea6c22323905d2070c
-Merge: 8a6f3e40d 0ebbc1880
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Tue Oct 6 23:18:44 2020 +0000
-
-    Merge "Removing tracing for a gone flake" into ub-launcher3-master
-
-commit 8a6f3e40d0321217c624055db7929c397e455e0c
-Merge: e29a9f796 565ed4ff6
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Tue Oct 6 22:49:40 2020 +0000
-
-    Merge "Update Search UI" into ub-launcher3-master
-
-commit 0ebbc18803aaf8ef2f6db7d628d7ae1ce322e842
-Author: vadimt <vadimt@google.com>
-Date:   Tue Oct 6 14:52:27 2020 -0700
-
-    Removing tracing for a gone flake
-    
-    Bug: 156044202
-    Change-Id: Ice142bb941fee7b731f46c2073fab17d83bbc871
-
-commit 565ed4ff69b534812818a2b9aa8789a1aea210eb
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Wed Sep 30 10:42:07 2020 -0700
-
-    Update Search UI
-    
-    [preview attached to bug]
-    
-    Bug: 169438169
-    Test: Manual
-    Change-Id: I085f3dd38ac373c1afab82a637ec08715a6e0cc5
-
-commit e29a9f7961e6db0915bc028ef7e871dcb2c8bde0
-Merge: 2c5ed10ff be17bdcd2
-Author: Jayaprakash Sundararaj <jayaprakashs@google.com>
-Date:   Tue Oct 6 21:00:20 2020 +0000
-
-    Merge "[Search] Add logging to People and badding as to icons." into ub-launcher3-master
-
-commit be17bdcd221f501c45876abe2249c1007858d0c0
-Author: jayaprakashs <jayaprakashs@google.com>
-Date:   Mon Oct 5 09:01:52 2020 -0700
-
-    [Search] Add logging to People and badding as to icons.
-    
-    Change-Id: I65948a2faca436216a94aa46139d425b8eade827
-
-commit 2c5ed10ffa1a870de35f9b3c0c558270aff498dd
-Merge: b2b65a1ef 8ed9707cf
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Tue Oct 6 18:40:57 2020 +0000
-
-    Merge "[Live Tile] Support launching another task (other than the current running task) in Overview" into ub-launcher3-master
-
-commit b2b65a1ef58b020923d112051535b6eb83b582df
-Merge: 3cf264f49 4c14f4b9e
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Tue Oct 6 17:45:35 2020 +0000
-
-    Merge "Avoid double search item highlight" into ub-launcher3-master
-
-commit 8ed9707cf3a4300cb61942f08f0752c80eed086b
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Mon Sep 14 23:25:37 2020 -0700
-
-    [Live Tile] Support launching another task (other than the current running task) in Overview
-    
-    - Get rid of the defer cancelation logic
-    - Render animation on the task view of the task being launched upon task view appeared callback
-    - Finish the recents animation upon the end of the recents window animation
-    
-    Fixes: 164926736
-    Test: manual
-    Change-Id: Ibffb6a9c74c235efc8615a22b0306551532c7b61
-
-commit 3cf264f498e37c482fa4c559bf48ffa791279585
-Author: Schneider Victor-tulias <victortulias@google.com>
-Date:   Tue Sep 22 12:58:38 2020 -0700
-
-    Prevent hotseat updates if it is visible to the user.
-    
-    Test: manual
-    
-    Fixes: 168653219
-    
-    Changing app icons under the user's finger could be disruptive. Added a checks for whether the hotseatand all apps predictions are visible and callbacks to update them when they become hidden.
-    
-    Change-Id: Ib9e6e904e9f662ecfaeea6a2fe21d1d81ba39b96
-
-commit b6aff1f56d55a36256446ec3970d92e9da39b98c
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Mon Oct 5 16:08:35 2020 -0700
-
-    Fix NPE inside RecentsOrientedState
-    
-    Bug: 169963211
-    Change-Id: I86dd337dc1b862f3fa99b91b47fa250076233f96
-
-commit eab40983b9a48b933bde5ca95a82ebd4d83b233d
-Merge: 83ce7c0b5 020e628f2
-Author: Jonathan Miranda <jonmiranda@google.com>
-Date:   Mon Oct 5 22:20:27 2020 +0000
-
-    Merge "Add shadow radius to windows during app launch / close animations." into ub-launcher3-master
-
-commit 83ce7c0b5e461386bb92883a8d6cefe8365cd9ae
-Merge: 679d920bf d6b1f3c08
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 5 19:18:39 2020 +0000
-
-    Merge "Action icon should be used as a badge instead of main icon" into ub-launcher3-master
-
-commit 679d920bf5151cffed4e8186c12c25d8d7907af9
-Merge: e108cc609 0c943966d
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 5 19:13:50 2020 +0000
-
-    Merge "Add null check for input receiver before updating batching" into ub-launcher3-master
-
-commit e108cc609d0a7fd58f0c7e16ce45fa79be6dd272
-Merge: 470403eb5 f622e42bf
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 5 18:39:58 2020 +0000
-
-    Merge "Removing unused proto extensions" into ub-launcher3-master
-
-commit 470403eb58879380e2edac2262dc7f40327b2a15
-Merge: a5130482a 1d7ed30db
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 5 18:29:54 2020 +0000
-
-    Merge "Remove widgets that no longer fit the workspace in their current spans." into ub-launcher3-master
-
-commit 4c14f4b9eda8332347c81e0cf51c5de4dbc06399
-Author: Samuel Fufa <sfufa@google.com>
-Date:   Mon Oct 5 10:50:00 2020 -0700
-
-    Avoid double search item highlight
-    
-    Change-Id: Ic2e28b18f6d5e3ed32cd5646bc3bb4789c378e57
-
-commit 0c943966d373d8ae7eef2b08e88ac44bf57d8a8d
-Author: Winson Chung <winsonc@google.com>
-Date:   Mon Oct 5 10:23:27 2020 -0700
-
-    Add null check for input receiver before updating batching
-    
-    - A change in the system (ie. sysui crash or nav mode change) could
-      cause the input monitor to be disposed before the swipe animation
-      settles
-    
-    Bug: 170121063
-    Test: Kill sysui while swiping up
-    
-    Change-Id: I1417b109fecdb98fae6197c7038dbe9307470853
-
-commit a5130482aee1b0592661bc1c6e178a0de7a163da
-Merge: b21819e18 7fcd74abb
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Mon Oct 5 17:14:21 2020 +0000
-
-    Merge "Suggest result should launch Bug: 169980192" into ub-launcher3-master
-
-commit d028937e74a9ea6d36e463de4c87ed37283bbdf6
-Author: Tracy Zhou <tracyzhou@google.com>
-Date:   Sat Oct 3 00:36:53 2020 -0700
-
-    [Live tile] Finish recents animation when the phone goes to sleep in live tile mode
-    
-    Fixes: 169988381
-    Test: manual
-    Change-Id: Ic71d3e6767eadb6854dbd46581bf9d3242c161a4
-
-commit 7fcd74abb399100ac8243be6ca28c09cc8adc8c8
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Fri Oct 2 19:20:11 2020 -0700
-
-    Suggest result should launch
-    Bug: 169980192
-    
-    Change-Id: I762245a5cc4740d093c9cb3b44a508e9e3f2b763
-
-commit b21819e181e99504c22c6ca028261a1f2665c6f9
-Merge: 931bce369 a762b0241
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Fri Oct 2 22:07:12 2020 +0000
-
-    Merge "Annotating Quick Switch CUJ for non-3-button modes" into ub-launcher3-master
-
-commit a762b02418695f5a1ff2f96586660de8c3610280
-Author: vadimt <vadimt@google.com>
-Date:   Fri Oct 2 13:56:28 2020 -0700
-
-    Annotating Quick Switch CUJ for non-3-button modes
-    
-    Bug: 169221288
-    Change-Id: I7145a9e28a2f0a789d19d2a0e3d15630c6e50f6a
-
-commit 931bce3697595a214023bc72923dad47a61d5711
-Merge: c935ba6b8 733e3c609
-Author: TreeHugger Robot <treehugger-gerrit@google.com>
-Date:   Fri Oct 2 19:19:50 2020 +0000
-
-    Merge "Moving some initializations to the background thread" into ub-launcher3-master
-
-commit c935ba6b8a2ec163533c0b19309dacb6199e6552
-Merge: a4111f250 58804ac52
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Fri Oct 2 18:26:06 2020 +0000
-
-    Merge "Adding stats log for add item flow" into ub-launcher3-master
-
-commit 733e3c609b7653a36e58747c881458ec00d98df8
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Tue Sep 29 10:32:32 2020 -0700
-
-    Moving some initializations to the background thread
-    
-    HandlerThread.getLooper blocks until the thread is ready. Instead
-    moving all looper dependency to the new thread itself.
-    
-    Change-Id: I240e8c56b855a991433a7fe93875059e6dab146b
-
-commit 58804ac5257f45dddbf7a6db35cf8f369ee1e88e
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Wed Sep 16 16:27:40 2020 -0700
-
-    Adding stats log for add item flow
-    
-    Bug: 169385783
-    Bug: 168167693
-    Change-Id: I37395f1b118727f67e0f14c02f945b8213b165c8
-
-commit a4111f250003328d1aef8bbaab59512208ec46cb
-Merge: 8d14dbe04 f6b72c4ad
-Author: Hilary Huo <hhuo@google.com>
-Date:   Fri Oct 2 17:41:22 2020 +0000
-
-    Merge "[pixel-search] Bug fix: automatically launch screenshot + center&crop remoteaction icon" into ub-launcher3-master
-
-commit f622e42bf6983d3adb95386bfd6375d281f1d4f2
-Author: Sunny Goyal <sunnygoyal@google.com>
-Date:   Fri Oct 2 10:35:56 2020 -0700
-
-    Removing unused proto extensions
-    
-    Change-Id: I6d0319c99934dad5176b6f70b895a4ca772ec45f
-
-commit d6b1f3c086f9ac097cd03e1ee898b153478ec11a
-Author: Hyunyoung Song <hyunyoungs@google.com>
-Date:   Fri Oct 2 00:26:35 2020 -0700
-
-    Action icon should be used as a badge instead of main icon
-    
-    Bug: 169796517
-    Change-Id: I3f07fdc2ae6e1af463701f942c26c3ca5d836ee2
-
-commit f6b72c4ad1d2e082441a64c4d6a5a02ee8a251ca
-Author: Hilary Huo <hhuo@google.com>
-Date:   Thu Oct 1 12:26:48 2020 -0700
-
-    [pixel-search] Bug fix: automatically launch screenshot + center&crop remoteaction icon
-    
-    Bug: b/169330678
-    Change-Id: Id5f8a0ce6d68f7ed9e4d1ff258ee3772229eb63b
-
-commit 1d7ed30dba4b2c71fc7b0981532a872a13e5aedb
-Author: Jon Miranda <jonmiranda@google.com>
-Date:   Wed Sep 23 12:15:43 2020 -0700
-
-    Remove widgets that no longer fit the workspace in their current spans.
-    
-    This can happen when display size changes.
-    We compare span sizes of widget in the db to the min sizes of the widget
-    in the current display size. If the widget can no longer fit in its existing
-    spans, we remove it.
-    
-    Also update test widgets to have minWidth/minHeight of 1dp. This ensures that
-    the spanX, spanY, min* values remain consistent between different test devices.
-    
-    Bug: 168818961
-    Change-Id: I723372e4582658f78b2f23ced9073cb77977a6b8
-
-commit 020e628f22cc7975beab439c6da26af2f9ebc15b
-Author: Jon Miranda <jonmiranda@google.com>
-Date:   Mon Sep 28 17:01:42 2020 -0700
-
-    Add shadow radius to windows during app launch / close animations.
-    
-    Bug: 168608912
-    Change-Id: I2ec50b0b3711c0861659f9c641bbc05fcdeaab45
diff --git a/ext_tests/res/values/overrides.xml b/ext_tests/res/values/overrides.xml
deleted file mode 100644
index 3f071d4..0000000
--- a/ext_tests/res/values/overrides.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="test_information_handler_class" translatable="false">com.android.launcher3.testing.DebugTestInformationHandler</string>
-</resources>
-
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
deleted file mode 100644
index 29b24b7..0000000
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.testing;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-
-import android.app.Activity;
-import android.app.Application;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Bundle;
-import android.system.Os;
-
-import androidx.annotation.Keep;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.ShortcutAndWidgetContainer;
-import com.android.launcher3.testing.shared.TestProtocol;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Class to handle requests from tests, including debug ones.
- */
-public class DebugTestInformationHandler extends TestInformationHandler {
-    private static Collection<String> sEvents;
-    private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
-    private static final Map<Activity, Boolean> sActivities =
-            Collections.synchronizedMap(new WeakHashMap<>());
-    private static int sActivitiesCreatedCount = 0;
-
-    public DebugTestInformationHandler(Context context) {
-        init(context);
-        if (sActivityLifecycleCallbacks == null) {
-            sActivityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
-                @Override
-                public void onActivityCreated(Activity activity, Bundle bundle) {
-                    sActivities.put(activity, true);
-                    ++sActivitiesCreatedCount;
-                }
-
-                @Override
-                public void onActivityStarted(Activity activity) {
-                }
-
-                @Override
-                public void onActivityResumed(Activity activity) {
-                }
-
-                @Override
-                public void onActivityPaused(Activity activity) {
-                }
-
-                @Override
-                public void onActivityStopped(Activity activity) {
-                }
-
-                @Override
-                public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
-                }
-
-                @Override
-                public void onActivityDestroyed(Activity activity) {
-                }
-            };
-            ((Application) context.getApplicationContext())
-                    .registerActivityLifecycleCallbacks(sActivityLifecycleCallbacks);
-        }
-    }
-
-    private static void runGcAndFinalizersSync() {
-        Runtime.getRuntime().gc();
-        Runtime.getRuntime().runFinalization();
-
-        final CountDownLatch fence = new CountDownLatch(1);
-        createFinalizationObserver(fence);
-        try {
-            do {
-                Runtime.getRuntime().gc();
-                Runtime.getRuntime().runFinalization();
-            } while (!fence.await(100, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException ex) {
-            throw new RuntimeException(ex);
-        }
-    }
-
-    // Create the observer in the scope of a method to minimize the chance that
-    // it remains live in a DEX/machine register at the point of the fence guard.
-    // This must be kept to avoid R8 inlining it.
-    @Keep
-    private static void createFinalizationObserver(CountDownLatch fence) {
-        new Object() {
-            @Override
-            protected void finalize() throws Throwable {
-                try {
-                    fence.countDown();
-                } finally {
-                    super.finalize();
-                }
-            }
-        };
-    }
-
-    @Override
-    public Bundle call(String method, String arg, @Nullable Bundle extras) {
-        final Bundle response = new Bundle();
-        switch (method) {
-            case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
-                return getLauncherUIProperty(Bundle::putInt,
-                        l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
-            }
-
-            case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
-                TestProtocol.sDebugTracing = true;
-                return response;
-
-            case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
-                TestProtocol.sDebugTracing = false;
-                return response;
-
-            case TestProtocol.REQUEST_PID: {
-                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
-                return response;
-            }
-
-            case TestProtocol.REQUEST_FORCE_GC: {
-                runGcAndFinalizersSync();
-                return response;
-            }
-
-            case TestProtocol.REQUEST_START_EVENT_LOGGING: {
-                sEvents = new ArrayList<>();
-                TestLogging.setEventConsumer(
-                        (sequence, event) -> {
-                            final Collection<String> events = sEvents;
-                            if (events != null) {
-                                synchronized (events) {
-                                    events.add(sequence + '/' + event);
-                                }
-                            }
-                        });
-                return response;
-            }
-
-            case TestProtocol.REQUEST_STOP_EVENT_LOGGING: {
-                TestLogging.setEventConsumer(null);
-                sEvents = null;
-                return response;
-            }
-
-            case TestProtocol.REQUEST_GET_TEST_EVENTS: {
-                if (sEvents == null) {
-                    // sEvents can be null if Launcher died and restarted after
-                    // REQUEST_START_EVENT_LOGGING.
-                    return response;
-                }
-
-                synchronized (sEvents) {
-                    response.putStringArrayList(
-                            TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
-                }
-                return response;
-            }
-
-            case TestProtocol.REQUEST_REINITIALIZE_DATA: {
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    MODEL_EXECUTOR.execute(() -> {
-                        LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
-                        model.getModelDbController().createEmptyDB();
-                        MAIN_EXECUTOR.execute(model::forceReload);
-                    });
-                    return response;
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-
-            case TestProtocol.REQUEST_CLEAR_DATA: {
-                final long identity = Binder.clearCallingIdentity();
-                try {
-                    MODEL_EXECUTOR.execute(() -> {
-                        LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
-                        model.getModelDbController().createEmptyDB();
-                        model.getModelDbController().clearEmptyDbFlag();
-                        MAIN_EXECUTOR.execute(model::forceReload);
-                    });
-                    return response;
-                } finally {
-                    Binder.restoreCallingIdentity(identity);
-                }
-            }
-
-            case TestProtocol.REQUEST_HOTSEAT_ICON_NAMES: {
-                return getLauncherUIProperty(Bundle::putStringArrayList, l -> {
-                    ShortcutAndWidgetContainer hotseatIconsContainer =
-                            l.getHotseat().getShortcutsAndWidgets();
-                    ArrayList<String> hotseatIconNames = new ArrayList<>();
-
-                    for (int i = 0; i < hotseatIconsContainer.getChildCount(); i++) {
-                        // Use unchecked cast to catch changes in hotseat layout
-                        BubbleTextView icon = (BubbleTextView) hotseatIconsContainer.getChildAt(i);
-                        hotseatIconNames.add((String) icon.getText());
-                    }
-
-                    return hotseatIconNames;
-                });
-            }
-
-            case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
-                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
-                return response;
-            }
-
-            case TestProtocol.REQUEST_GET_ACTIVITIES: {
-                response.putStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        sActivities.keySet().stream().map(
-                                a -> a.getClass().getSimpleName() + " ("
-                                        + (a.isDestroyed() ? "destroyed" : "current") + ")")
-                                .toArray(String[]::new));
-                return response;
-            }
-
-            case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED:
-                return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new);
-
-            default:
-                return super.call(method, arg, extras);
-        }
-    }
-}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index 48650aa..df09124 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -120,6 +120,16 @@
             android:layout_height="1dp"
             android:layout_weight="1"
             android:visibility="gone" />
+
+        <Button
+            android:id="@+id/action_save_app_pair"
+            style="@style/GoOverviewActionButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:drawableStart="@drawable/ic_save_app_pair_up_down"
+            android:text="@string/action_save_app_pair"
+            android:theme="@style/ThemeControlHighlightWorkspaceColor"
+            android:visibility="gone" />
     </LinearLayout>
 
 </com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/go/quickstep/res/values-my/strings.xml b/go/quickstep/res/values-my/strings.xml
index cbb485a..5fcb5bd 100644
--- a/go/quickstep/res/values-my/strings.xml
+++ b/go/quickstep/res/values-my/strings.xml
@@ -9,11 +9,11 @@
     <string name="dialog_cancel" msgid="6464336969134856366">"မလုပ်တော့"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"ဆက်တင်များ"</string>
     <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို ဘာသာပြန်ပါ (သို့) နားထောင်ပါ"</string>
-    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"သင့်ဖန်သားပြင်ပေါ်ရှိ စာသား၊ ဝဘ်လိပ်စာနှင့် ဖန်သားပြင်ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များကို Google နှင့် မျှဝေနိုင်သည်။\n\nသင်မျှဝေသည့် အချက်အလက်များကို ပြောင်းရန် "<b>"ဆက်တင်များ &gt; အက်ပ်များ &gt; မူရင်းအက်ပ်များ &gt; ဒစ်ဂျစ်တယ် Assistant အက်ပ်"</b>" သို့ သွားပါ။"</string>
+    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"သင့်ဖန်သားပြင်ပေါ်ရှိ စာသား၊ ဝဘ်လိပ်စာနှင့် ဖန်သားပြင်ဓာတ်ပုံများကဲ့သို့ အချက်အလက်များကို Google နှင့် မျှဝေနိုင်သည်။\n\nသင်မျှဝေသည့် အချက်အလက်များကို ပြောင်းရန် "<b>"ဆက်တင်များ &gt; အက်ပ်များ &gt; မူရင်းအက်ပ်များ &gt; ဒစ်ဂျစ်တယ်အထောက်အကူ အက်ပ်"</b>" သို့ သွားပါ။"</string>
     <string name="assistant_not_selected_title" msgid="5017072974603345228">"ဤဝန်ဆောင်မှုကို အသုံးပြုရန် assistant ရွေးပါ"</string>
-    <string name="assistant_not_selected_text" msgid="3244613673884359276">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ် assistant အက်ပ် ရွေးပါ"</string>
+    <string name="assistant_not_selected_text" msgid="3244613673884359276">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ်အထောက်အကူ အက်ပ် ရွေးပါ"</string>
     <string name="assistant_not_supported_title" msgid="1675788067597484142">"ဤဝန်ဆောင်မှုကို သုံးရန် assistant ကို ပြောင်းပါ"</string>
-    <string name="assistant_not_supported_text" msgid="1708031078549268884">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ် assistant အက်ပ်ကို ပြောင်းပါ"</string>
+    <string name="assistant_not_supported_text" msgid="1708031078549268884">"ဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် (သို့) ဘာသာပြန်ဆိုရန် ‘ဆက်တင်များ’ တွင် ဒစ်ဂျစ်တယ်အထောက်အကူ အက်ပ်ကို ပြောင်းပါ"</string>
     <string name="tooltip_listen" msgid="7634466447860989102">"ဤဖန်သားပြင်ပေါ်ရှိ စာသားကို နားထောင်ရန် ဤနေရာကို တို့ပါ"</string>
     <string name="tooltip_translate" msgid="4184845868901542567">"ဤဖန်သားပြင်ပေါ်ရှိ စာသားကို ဘာသာပြန်ဆိုရန် ဤနေရာကို တို့ပါ"</string>
     <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"ဤအက်ပ်ကို မျှဝေ၍မရပါ"</string>
diff --git a/go/quickstep/res/values-ne/strings.xml b/go/quickstep/res/values-ne/strings.xml
index 11a70dd..e66f063 100644
--- a/go/quickstep/res/values-ne/strings.xml
+++ b/go/quickstep/res/values-ne/strings.xml
@@ -8,7 +8,7 @@
     <string name="dialog_acknowledge" msgid="2804025517675853172">"बुझेँ"</string>
     <string name="dialog_cancel" msgid="6464336969134856366">"रद्द गर्नुहोस्"</string>
     <string name="dialog_settings" msgid="6564397136021186148">"सेटिङ"</string>
-    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"स्क्रिनमा देखिने पाठ अनुवाद गरियोस् वा पढेर सुनाइयोस्"</string>
+    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"स्क्रिनमा देखिने पाठ अनुवाद गर्नुहोस् वा पढेर सुनाउनुहोस्"</string>
     <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"तपाईंको स्क्रिनमा देखिने पाठ, वेब ठेगाना र स्क्रिनसटलगायतका जानकारी Google सँग सेयर गर्न सकिन्छ।\n\nकुन कुन जानकारी सेयर गर्न दिने भन्ने सेटिङ बदल्न "<b>"सेटिङ &gt; एप &gt; डिफल्ट एप &gt; डिजिटल सहायक एप"</b>" मा जानुहोस्।"</string>
     <string name="assistant_not_selected_title" msgid="5017072974603345228">"तपाईं यो सुविधा चलाउन चाहनुहुन्छ भने कुनै सहायक छनौट गर्नुहोस्"</string>
     <string name="assistant_not_selected_text" msgid="3244613673884359276">"तपाईं आफ्नो स्क्रिनमा देखिने पाठ सुन्न वा अनुवाद गर्न चाहनुहुन्छ भने सेटिङमा गई कुनै डिजिटल सहायक एप छनौट गर्नुहोस्"</string>
diff --git a/go/quickstep/res/values/config.xml b/go/quickstep/res/values/config.xml
index 796d14d..147dd96 100644
--- a/go/quickstep/res/values/config.xml
+++ b/go/quickstep/res/values/config.xml
@@ -21,4 +21,7 @@
     <bool name="enable_niu_actions">true</bool>
 
     <string name="task_overlay_factory_class" translatable="false">com.android.quickstep.TaskOverlayFactoryGo</string>
+
+    <!-- String representing the intent to delete a package. -->
+    <string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;B.android.intent.extra.RETURN_RESULT=true;end</string>
 </resources>
\ No newline at end of file
diff --git a/go/res/xml/device_profiles.xml b/go/quickstep/res/xml/device_profiles.xml
similarity index 100%
rename from go/res/xml/device_profiles.xml
rename to go/quickstep/res/xml/device_profiles.xml
diff --git a/go/quickstep/src/com/android/launcher3/AppSharing.java b/go/quickstep/src/com/android/launcher3/AppSharing.java
index cb1f1c7..e15b132 100644
--- a/go/quickstep/src/com/android/launcher3/AppSharing.java
+++ b/go/quickstep/src/com/android/launcher3/AppSharing.java
@@ -27,9 +27,12 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import androidx.core.content.FileProvider;
@@ -44,6 +47,9 @@
 import com.android.launcher3.views.ActivityContext;
 
 import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
 
 /**
  * Defines the Share system shortcut and its factory.
@@ -64,14 +70,17 @@
 
     private static final String TAG = "AppSharing";
     private static final String FILE_PROVIDER_SUFFIX = ".overview.fileprovider";
-    private static final String APP_EXSTENSION = ".apk";
+    private static final String APP_EXTENSION = ".apk";
     private static final String APP_MIME_TYPE = "application/application";
 
     private final String mSharingComponent;
     private AppShareabilityManager mShareabilityMgr;
 
     private AppSharing(Launcher launcher) {
-        mSharingComponent = launcher.getText(R.string.app_sharing_component).toString();
+        String sharingComponent = Settings.Secure.getString(launcher.getContentResolver(),
+                Settings.Secure.NEARBY_SHARING_COMPONENT);
+        mSharingComponent = TextUtils.isEmpty(sharingComponent) ? launcher.getText(
+                R.string.app_sharing_component).toString() : sharingComponent;
     }
 
     private Uri getShareableUri(Context context, String path, String displayName) {
@@ -108,6 +117,9 @@
         private final PopupDataProvider mPopupDataProvider;
         private final boolean mSharingEnabledForUser;
 
+        private final Set<View> mBoundViews = Collections.newSetFromMap(new WeakHashMap<>());
+        private boolean mIsEnabled = true;
+
         public Share(Launcher target, ItemInfo itemInfo, View originalView) {
             super(R.drawable.ic_share, R.string.app_share_drop_target_label, target, itemInfo,
                     originalView);
@@ -124,10 +136,23 @@
         }
 
         @Override
+        public void setIconAndLabelFor(View iconView, TextView labelView) {
+            super.setIconAndLabelFor(iconView, labelView);
+            mBoundViews.add(iconView);
+            mBoundViews.add(labelView);
+        }
+
+        @Override
+        public void setIconAndContentDescriptionFor(ImageView view) {
+            super.setIconAndContentDescriptionFor(view);
+            mBoundViews.add(view);
+        }
+
+        @Override
         public void onClick(View view) {
             ActivityContext.lookupContext(view.getContext())
                     .getStatsLogManager().logger().log(LAUNCHER_SYSTEM_SHORTCUT_APP_SHARE_TAP);
-            if (!isEnabled()) {
+            if (!mIsEnabled) {
                 showCannotShareToast(view.getContext());
                 return;
             }
@@ -147,7 +172,7 @@
                 PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
                 sourceDir = packageInfo.applicationInfo.sourceDir;
                 appLabel = packageManager.getApplicationLabel(packageInfo.applicationInfo)
-                        .toString() + APP_EXSTENSION;
+                        + APP_EXTENSION;
             } catch (Exception e) {
                 Log.e(TAG, "Could not find info for package \"" + packageName + "\"");
                 return;
@@ -175,9 +200,6 @@
                 return;
             }
             checkShareability(/* requestUpdateIfUnknown */ false);
-            mTarget.runOnUiThread(() -> {
-                mPopupDataProvider.redrawSystemShortcuts();
-            });
         }
 
         private void checkShareability(boolean requestUpdateIfUnknown) {
@@ -207,6 +229,17 @@
             int duration = Toast.LENGTH_SHORT;
             Toast.makeText(context, text, duration).show();
         }
+
+        public void setEnabled(boolean isEnabled) {
+            if (mIsEnabled != isEnabled) {
+                mIsEnabled = isEnabled;
+                mBoundViews.forEach(v -> v.setEnabled(isEnabled));
+            }
+        }
+
+        public boolean isEnabled() {
+            return mIsEnabled;
+        }
     }
 
     /**
diff --git a/go/quickstep/src/com/android/launcher3/BuildConfig.java b/go/quickstep/src/com/android/launcher3/BuildConfig.java
new file mode 100644
index 0000000..cfcda39
--- /dev/null
+++ b/go/quickstep/src/com/android/launcher3/BuildConfig.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+public final class BuildConfig {
+    public static final String APPLICATION_ID = "com.android.launcher3";
+
+    public static final boolean IS_STUDIO_BUILD = false;
+    /**
+     * Flag to state if the QSB is on the first screen and placed on the top,
+     * this can be overwritten in other launchers with a different value, if needed.
+     */
+    public static final boolean QSB_ON_FIRST_SCREEN = true;
+
+    /**
+     * Flag to state if the widget on the top of the first screen should be shown.
+     */
+    public static final boolean WIDGET_ON_FIRST_SCREEN = false;
+
+    /**
+     * Flag to control various developer centric features
+     */
+    public static final boolean IS_DEBUG_DEVICE = false;
+
+    // Flag to control widgets support in Launcher
+    public static final boolean WIDGETS_ENABLED = false;
+    // Flag to control notification dots support in Launcher
+    public static final boolean NOTIFICATION_DOTS_ENABLED = false;
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
index 0d0f700..556d29c 100644
--- a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
@@ -35,6 +35,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.launcher3.model.AppShareabilityDatabase.ShareabilityDao;
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
@@ -47,7 +48,7 @@
  * Each app's status is retrieved from the Play Store's API. Statuses are cached in order
  * to limit extraneous calls to that API (which can be time-consuming).
  */
-public class AppShareabilityManager {
+public class AppShareabilityManager implements SafeCloseable {
     @Retention(SOURCE)
     @IntDef({
         ShareabilityStatus.UNKNOWN,
@@ -194,6 +195,11 @@
         }
     }
 
+    @Override
+    public void close() {
+        mDatabase.close();
+    }
+
     /**
      * Provides a testable instance of this class
      * This instance allows database queries on the main thread
diff --git a/go/res/values-v26/bools.xml b/go/res/values-v26/bools.xml
deleted file mode 100644
index 1584734..0000000
--- a/go/res/values-v26/bools.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources>
-    <bool name="notification_dots_enabled">false</bool>
-</resources>
-
diff --git a/go/res/values/override.xml b/go/res/values/override.xml
deleted file mode 100644
index 268cb98..0000000
--- a/go/res/values/override.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2017 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-<resources>
-    <!-- String representing the intent to delete a package. -->
-    <string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;B.android.intent.extra.RETURN_RESULT=true;end</string>
-</resources>
\ No newline at end of file
diff --git a/go/src/com/android/launcher3/model/LauncherBinder.java b/go/src/com/android/launcher3/model/LauncherBinder.java
deleted file mode 100644
index 7a0dce8..0000000
--- a/go/src/com/android/launcher3/model/LauncherBinder.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.model;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-
-/**
- * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
- */
-public class LauncherBinder extends BaseLauncherBinder {
-
-    public LauncherBinder(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacks) {
-        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
-    }
-
-    @Override
-    public void bindDeepShortcuts() {
-    }
-
-    @Override
-    public void bindWidgets() {
-    }
-
-    @Override
-    public void bindSmartspaceWidget() {
-    }
-}
diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java
deleted file mode 100644
index 1aa5d03..0000000
--- a/go/src/com/android/launcher3/model/WidgetsModel.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.model;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.UserHandle;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.icons.ComponentWithLabelAndIcon;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Widgets data model that is used by the adapters of the widget views and controllers.
- *
- * <p> The widgets and shortcuts are organized using package name as its index.
- */
-public class WidgetsModel {
-
-    // True is the widget support is disabled.
-    public static final boolean GO_DISABLE_WIDGETS = true;
-    public static final boolean GO_DISABLE_NOTIFICATION_DOTS = true;
-
-    private static final ArrayList<WidgetsListBaseEntry> EMPTY_WIDGET_LIST = new ArrayList<>();
-
-    /**
-     * Returns a list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row are
-     * sorted (based on label and user), but the overall list of {@link WidgetsListBaseEntry}s is
-     * not sorted. This list is sorted at the UI when using
-     * {@link com.android.launcher3.widget.picker.WidgetsDiffReporter}
-     *
-     * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
-     */
-    public synchronized ArrayList<WidgetsListBaseEntry> getWidgetsListForPicker(Context context) {
-        return EMPTY_WIDGET_LIST;
-    }
-
-    /** Returns a mapping of packages to their widgets without static shortcuts. */
-    public synchronized Map<PackageUserKey, List<WidgetItem>> getAllWidgetsWithoutShortcuts() {
-        return Map.of();
-    }
-
-    /**
-     * @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<ComponentWithLabelAndIcon> update(LauncherAppState app,
-            @Nullable PackageUserKey packageUser) {
-        return Collections.emptyList();
-    }
-
-
-    public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
-            LauncherAppState app) {
-    }
-
-    public WidgetItem getWidgetProviderInfoByProviderName(
-            ComponentName providerName, UserHandle user) {
-        return null;
-    }
-
-    /** Returns {@link PackageItemInfo} of a pending widget. */
-    public static PackageItemInfo newPendingItemInfo(
-            Context context, ComponentName provider, UserHandle userHandle) {
-        return new PackageItemInfo(provider.getPackageName(), userHandle);
-    }
-}
\ No newline at end of file
diff --git a/go/src/com/android/launcher3/util/AbsGridOccupancy.java b/go/src/com/android/launcher3/util/AbsGridOccupancy.java
deleted file mode 100644
index 4a46bd1..0000000
--- a/go/src/com/android/launcher3/util/AbsGridOccupancy.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-/**
- * Defines method to find the next vacant cell on a grid.
- * This uses the default top-down, left-right approach and can be over-written through
- * code swaps in different launchers.
- */
-public abstract class AbsGridOccupancy {
-
-    /**
-     * Find the first vacant cell, if there is one.
-     *
-     * @param vacantOut Holds the x and y coordinate of the vacant cell
-     * @param spanX Horizontal cell span.
-     * @param spanY Vertical cell span.
-     *
-     * @return true if a vacant cell was found
-     */
-    protected boolean findVacantCell(int[] vacantOut, boolean[][] cells, int countX, int countY,
-            int spanX, int spanY) {
-        for (int y = 0; (y + spanY) <= countY; y++) {
-            for (int x = 0; (x + spanX) <= countX; x++) {
-                boolean available = !cells[x][y];
-                out:
-                for (int i = x; i < x + spanX; i++) {
-                    for (int j = y; j < y + spanY; j++) {
-                        available = available && !cells[i][j];
-                        if (!available) break out;
-                    }
-                }
-                if (available) {
-                    vacantOut[0] = x;
-                    vacantOut[1] = y;
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-}
diff --git a/gradle.properties b/gradle.properties
deleted file mode 100644
index d5c1d77..0000000
--- a/gradle.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# Until all the dependencies move to android X
-android.useAndroidX = true
-android.enableJetifier = true
-org.gradle.parallel=true
-
-ANDROID_X_VERSION=1+
-
-GRADLE_CLASS_PATH=com.android.tools.build:gradle:3.5.1
-
-PROTOBUF_CLASS_PATH=com.google.protobuf:protobuf-gradle-plugin:0.8.8
-PROTOBUF_DEPENDENCY=com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-7
-
-BUILD_TOOLS_VERSION=28.0.3
-COMPILE_SDK=android-S
diff --git a/lint-baseline-common-deps-lib.xml b/lint-baseline-common-deps-lib.xml
deleted file mode 100644
index e52f8fb..0000000
--- a/lint-baseline-common-deps-lib.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
-        errorLine1="        android:topLeftRadius=&quot;?android:attr/dialogCornerRadius&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="6"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
-        errorLine1="        android:topRightRadius=&quot;?android:attr/dialogCornerRadius&quot; />"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="7"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
-        errorLine1="    &lt;style name=&quot;Widget.DeviceDefault.Button.Rounded.Colored&quot; parent=&quot;@android:style/Widget.DeviceDefault.Button.Colored&quot;>"
-        errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/values/styles.xml"
-            line="287"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
-        errorLine1="    &lt;corners android:radius=&quot;@android:dimen/system_app_widget_background_radius&quot; />"
-        errorLine2="             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
-            line="20"
-            column="14"/>
-    </issue>
-
-</issues>
diff --git a/lint-baseline-go-res-lib.xml b/lint-baseline-go-res-lib.xml
deleted file mode 100644
index c5669f2..0000000
--- a/lint-baseline-go-res-lib.xml
+++ /dev/null
@@ -1,576 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                           ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                    ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                                   ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="68"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                            ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="45"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
-        errorLine1="            widgetView.updateAppWidgetSize(new Bundle(), sizes);"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
-            line="399"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
-        errorLine1="        potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);"
-        errorLine2="                          ~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
-            line="248"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
-        errorLine1="        potentialTaskRect.inset("
-        errorLine2="                          ~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
-            line="249"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
-        errorLine1="        outRect.inset(Math.max(insets.left, sideMargin), Math.max(insets.top, topMargin),"
-        errorLine2="                ~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
-            line="291"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.graphics.Rect#inset`"
-        errorLine1="        gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);"
-        errorLine2="                 ~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/BaseActivityInterface.java"
-            line="315"
-            column="18"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowManager#getCurrentWindowMetrics`"
-        errorLine1="                    .getCurrentWindowMetrics().getWindowInsets();"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
-            line="236"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowMetrics#getWindowInsets`"
-        errorLine1="                    .getCurrentWindowMetrics().getWindowInsets();"
-        errorLine2="                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
-            line="236"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
-        errorLine1="            if (mContext.getDisplay() != null) {"
-        errorLine2="                         ~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
-            line="115"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
-        errorLine1="                mContext.getDisplay().getRealSize(mDisplaySize);"
-        errorLine2="                         ~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java"
-            line="116"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.content.ContextWrapper#getDisplay`"
-        errorLine1="        Display display = getDisplay();"
-        errorLine2="                          ~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
-            line="153"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="                    List.of(new Rect(0, 0, metrics.widthPixels, metrics.heightPixels)));"
-        errorLine2="                         ~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java"
-            line="158"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetHostView#resetColorResources`"
-        errorLine1="            resetColorResources();"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="137"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="            mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
-        errorLine2="                                             ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="367"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="                mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
-        errorLine2="                                                 ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="390"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
-        errorLine1="                (ATLEAST_S &amp;&amp; maxResizeWidth > 0)"
-        errorLine2="                              ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="91"
-            column="31"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
-        errorLine1="                        ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
-        errorLine2="                                                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="92"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
-        errorLine1="                (ATLEAST_S &amp;&amp; maxResizeHeight > 0)"
-        errorLine2="                              ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="95"
-            column="31"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
-        errorLine1="                        ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="96"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="        if (ATLEAST_S &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= maxSpanX"
-        errorLine2="                         ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="101"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="        if (ATLEAST_S &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= maxSpanX"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="101"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="                &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= maxSpanY) {"
-        errorLine2="                   ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="102"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="                &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= maxSpanY) {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="102"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="            spanX = targetCellWidth;"
-        errorLine2="                    ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="103"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="            spanY = targetCellHeight;"
-        errorLine2="                    ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="104"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.content.Context#getDisplay`"
-        errorLine1="        final Display display = mContext.getDisplay();"
-        errorLine2="                                         ~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java"
-            line="94"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
-        errorLine1="            return (int) (100 * info.getLoadingProgress());"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
-            line="338"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="    private List&lt;WidgetsListBaseEntry> mAllWidgets = List.of();"
-        errorLine2="                                                          ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
-            line="64"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="    private List&lt;ItemInfo> mRecommendedWidgets = List.of();"
-        errorLine2="                                                      ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
-            line="66"
-            column="55"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `new android.view.SurfaceControlViewHost`"
-        errorLine1="                    .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="91"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#getSurfacePackage`"
-        errorLine1="            surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="93"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#setView`"
-        errorLine1="                host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
-        errorLine2="                     ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="127"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 29)"
-        errorLine1="        result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
-        errorLine2="                                                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="132"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.SurfaceControlViewHost#release`"
-        errorLine1="                mSurfaceControlViewHost.release();"
-        errorLine2="                                        ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="149"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.graphics.Outline#setPath`"
-        errorLine1="        outline.setPath(mPath);"
-        errorLine2="                ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
-            line="88"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
-        errorLine1="                ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
-            line="49"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `new android.widget.EdgeEffect`"
-        errorLine1="                ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
-            line="51"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowManager.LayoutParams#setFitInsetsTypes`"
-        errorLine1="        mWindowLayoutParams.setFitInsetsTypes(0);"
-        errorLine2="                            ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java"
-            line="316"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsets#getInsets`"
-        errorLine1="            Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
-        errorLine2="                                         ~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
-            line="118"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#systemBars`"
-        errorLine1="            Insets systemInsets = insets.getInsets(WindowInsets.Type.systemBars());"
-        errorLine2="                                                                     ~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java"
-            line="118"
-            column="70"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
-        errorLine1="            CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="193"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
-        errorLine1="                &amp;&amp; item.widgetInfo.previewLayout != Resources.ID_NULL) {"
-        errorLine2="                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="214"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 29): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
-        errorLine1="            launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="222"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.View#getWindowInsetsController`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsets.Type#ime`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                           ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `android.view.WindowInsetsController#hide`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                    ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 29): `java.util.List#of`"
-        errorLine1="            return new RecommendationTableData(List.of(), previewScale);"
-        errorLine2="                                                    ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
-            line="139"
-            column="53"/>
-    </issue>
-
-</issues>
diff --git a/lint-baseline-launcher3.xml b/lint-baseline-launcher3.xml
deleted file mode 100644
index 107a346..0000000
--- a/lint-baseline-launcher3.xml
+++ /dev/null
@@ -1,609 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 26): `android.os.UserManager#requestQuietModeEnabled`"
-        errorLine1="            showConfirm |= !userManager.requestQuietModeEnabled(!toState, userProfile);"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/WorkModeSwitch.java"
-            line="110"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                           ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                    ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsContainerView.java"
-            line="203"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                                   ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="68"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
-        errorLine1="                getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                            ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/allapps/AllAppsRecyclerView.java"
-            line="193"
-            column="45"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#updateAppWidgetSize`"
-        errorLine1="            widgetView.updateAppWidgetSize(new Bundle(), sizes);"
-        errorLine2="                       ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/AppWidgetResizeFrame.java"
-            line="399"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowManager#getCurrentWindowMetrics`"
-        errorLine1="                    .getCurrentWindowMetrics().getWindowInsets();"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
-            line="236"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowMetrics#getWindowInsets`"
-        errorLine1="                    .getCurrentWindowMetrics().getWindowInsets();"
-        errorLine2="                                               ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
-            line="236"
-            column="48"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
-        errorLine1="        folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);"
-        errorLine2="                                   ~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/DeviceProfile.java"
-            line="256"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
-        errorLine1="        return mContext.getResources().getFloat(resId);"
-        errorLine2="                                       ~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
-            line="73"
-            column="40"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`"
-        errorLine1="            resetColorResources();"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="137"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `java.util.List#of`"
-        errorLine1="            mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
-        errorLine2="                                             ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="367"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `java.util.List#of`"
-        errorLine1="                mColorExtractor.addLocation(List.of(mLastLocationRegistered));"
-        errorLine2="                                                 ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="390"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
-        errorLine1="                (ATLEAST_S &amp;&amp; maxResizeWidth > 0)"
-        errorLine2="                              ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="91"
-            column="31"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeWidth`"
-        errorLine1="                        ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)"
-        errorLine2="                                                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="92"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
-        errorLine1="                (ATLEAST_S &amp;&amp; maxResizeHeight > 0)"
-        errorLine2="                              ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="95"
-            column="31"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#maxResizeHeight`"
-        errorLine1="                        ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)"
-        errorLine2="                                                  ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="96"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="        if (ATLEAST_S &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= maxSpanX"
-        errorLine2="                         ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="101"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="        if (ATLEAST_S &amp;&amp; targetCellWidth >= minSpanX &amp;&amp; targetCellWidth &lt;= maxSpanX"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="101"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="                &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= maxSpanY) {"
-        errorLine2="                   ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="102"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="                &amp;&amp; targetCellHeight >= minSpanY &amp;&amp; targetCellHeight &lt;= maxSpanY) {"
-        errorLine2="                                                   ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="102"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellWidth`"
-        errorLine1="            spanX = targetCellWidth;"
-        errorLine2="                    ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="103"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#targetCellHeight`"
-        errorLine1="            spanY = targetCellHeight;"
-        errorLine2="                    ~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java"
-            line="104"
-            column="21"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`"
-        errorLine1="        return people.stream().filter(person -> person.getKey() != null)"
-        errorLine2="                                                       ~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
-            line="72"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
-        errorLine1="                .map(Person::getKey).sorted().toArray(String[]::new);"
-        errorLine2="                     ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
-            line="73"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.content.pm.LauncherActivityInfo#getLoadingProgress`"
-        errorLine1="            return (int) (100 * info.getLoadingProgress());"
-        errorLine2="                                     ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/util/PackageManagerHelper.java"
-            line="338"
-            column="38"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
-        errorLine1="                AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1752"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
-        errorLine1="                : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1753"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
-        errorLine1="                AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT"
-        errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1760"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
-        errorLine1="                : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);"
-        errorLine2="                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1761"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `java.util.List#of`"
-        errorLine1="    private List&lt;WidgetsListBaseEntry> mAllWidgets = List.of();"
-        errorLine2="                                                          ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
-            line="64"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `java.util.List#of`"
-        errorLine1="    private List&lt;ItemInfo> mRecommendedWidgets = List.of();"
-        errorLine2="                                                      ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/PopupDataProvider.java"
-            line="66"
-            column="55"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `new android.view.SurfaceControlViewHost`"
-        errorLine1="                    .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))"
-        errorLine2="                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="91"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#getSurfacePackage`"
-        errorLine1="            surfacePackage = mSurfaceControlViewHost.getSurfacePackage();"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="93"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#setView`"
-        errorLine1="                host.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight());"
-        errorLine2="                     ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="127"
-            column="22"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Cast from `SurfacePackage` to `Parcelable` requires API level 30 (current min is 26)"
-        errorLine1="        result.putParcelable(KEY_SURFACE_PACKAGE, surfacePackage);"
-        errorLine2="                                                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="132"
-            column="51"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#release`"
-        errorLine1="                mSurfaceControlViewHost.release();"
-        errorLine2="                                        ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java"
-            line="149"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.graphics.Outline#setPath`"
-        errorLine1="        outline.setPath(mPath);"
-        errorLine2="                ~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
-            line="88"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
-        errorLine1="                ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
-            line="49"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `new android.widget.EdgeEffect`"
-        errorLine1="                ? new EdgeEffect(context, attrs) : new EdgeEffect(context);"
-        errorLine2="                  ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/views/SpringRelativeLayout.java"
-            line="51"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 26): `android.view.WindowInsets#getTappableElementInsets`"
-        errorLine1="            return windowInsets.getTappableElementInsets().bottom > 0;"
-        errorLine2="                                ~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
-            line="190"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.graphics.Insets#bottom`"
-        errorLine1="            return windowInsets.getTappableElementInsets().bottom > 0;"
-        errorLine2="                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/SysUiScrim.java"
-            line="190"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`"
-        errorLine1="        int featureFlags = mProviderInfo.widgetFeatures;"
-        errorLine2="                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
-            line="93"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#loadDescription`"
-        errorLine1="            CharSequence description = mItem.widgetInfo.loadDescription(getContext());"
-        errorLine2="                                                        ~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="193"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
-        errorLine1="                &amp;&amp; item.widgetInfo.previewLayout != Resources.ID_NULL) {"
-        errorLine2="                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="214"
-            column="20"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 31 (current min is 26): `android.appwidget.AppWidgetProviderInfo#previewLayout`"
-        errorLine1="            launcherAppWidgetProviderInfo.initialLayout = item.widgetInfo.previewLayout;"
-        errorLine2="                                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetCell.java"
-            line="222"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.View#getWindowInsetsController`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsets.Type#ime`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                                           ~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="60"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `android.view.WindowInsetsController#hide`"
-        errorLine1="        getWindowInsetsController().hide(WindowInsets.Type.ime());"
-        errorLine2="                                    ~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="558"
-            column="37"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level R (current min is 26): `java.util.List#of`"
-        errorLine1="            return new RecommendationTableData(List.of(), previewScale);"
-        errorLine2="                                                    ~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java"
-            line="139"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
-        errorLine1="            : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);"
-        errorLine2="                                         ~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
-            line="178"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#setColorResources`"
-        errorLine1="                setColorResources(mWallpaperColorResources);"
-        errorLine2="                ~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
-            line="528"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 27 (current min is 26): `android.app.WallpaperManager#getWallpaperColors`"
-        errorLine1="                    : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);"
-        errorLine2="                                                            ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
-            line="288"
-            column="61"/>
-    </issue>
-
-</issues>
diff --git a/lint-baseline-res-lib.xml b/lint-baseline-res-lib.xml
deleted file mode 100644
index e52f8fb..0000000
--- a/lint-baseline-res-lib.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
-        errorLine1="        android:topLeftRadius=&quot;?android:attr/dialogCornerRadius&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="6"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
-        errorLine1="        android:topRightRadius=&quot;?android:attr/dialogCornerRadius&quot; />"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="7"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:style/Widget.DeviceDefault.Button.Colored` requires API level 28 (current min is 26)"
-        errorLine1="    &lt;style name=&quot;Widget.DeviceDefault.Button.Rounded.Colored&quot; parent=&quot;@android:style/Widget.DeviceDefault.Button.Colored&quot;>"
-        errorLine2="                                                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/values/styles.xml"
-            line="287"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
-        errorLine1="    &lt;corners android:radius=&quot;@android:dimen/system_app_widget_background_radius&quot; />"
-        errorLine2="             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
-            line="20"
-            column="14"/>
-    </issue>
-
-</issues>
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 23a22be..2ee9531 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,148 +1,37 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
 
     <issue
         id="NewApi"
-        message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
-            line="72"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
-            line="73"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 30 (current min is 26): `android.graphics.Outline#setPath`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
-            line="114"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 30 (current min is 26): `android.view.View#getWindowInsetsController`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="902"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 30 (current min is 26): `android.view.WindowInsets.Type#ime`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="902"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 30 (current min is 26): `android.view.WindowInsetsController#hide`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
-            line="902"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
-            line="114"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Call requires API level 31 (current min is 30): `android.appwidget.AppWidgetHostView#setColorResources`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
-            line="415"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
-            line="93"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1814"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1824"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1815"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
-            line="1823"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Method reference requires API level 28 (current min is 26): `Person::getKey`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
-            line="195"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Method reference requires API level 28 (current min is 26): `Person::getKey`">
-        <location
-            file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
-            line="73"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="6"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)">
-        <location
-            file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
-            line="7"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)">
+        message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
+        errorLine1='    &lt;corners android:radius="@android:dimen/system_app_widget_background_radius" /&gt;'
+        errorLine2="             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
             file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
-            line="20"/>
+            line="20"
+            column="14"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 26): `android.appwidget.AppWidgetHostView#resetColorResources`"
+        errorLine1="            resetColorResources();"
+        errorLine2="            ~~~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/apps/Launcher3/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java"
+            line="117"
+            column="13"/>
+    </issue>
+
+    <issue
+        id="NewApi"
+        message="Call requires API level 31 (current min is 30): `android.appwidget.AppWidgetHostView#setColorResources`"
+        errorLine1="            view.setColorResources(mWallpaperColorResources);"
+        errorLine2="                 ~~~~~~~~~~~~~~~~~">
+        <location
+            file="packages/apps/Launcher3/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java"
+            line="433"
+            column="18"/>
     </issue>
 
 </issues>
\ No newline at end of file
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index ec4f6fc..f14cebd 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -23,15 +23,23 @@
 }
 
 filegroup {
-    name: "launcher3-quickstep-robolectric-src",
-    path: "robolectric_tests",
-    srcs: ["robolectric_tests/src/**/*.java"],
+    name: "launcher3-quickstep-robo-src",
+    path: "tests/multivalentTests",
+    srcs: [
+        "tests/multivalentTests/src/**/*.java",
+        "tests/multivalentTests/src/**/*.kt",
+    ],
 }
 
 filegroup {
     name: "launcher3-quickstep-tests-src",
     path: "tests",
-    srcs: ["tests/src/**/*.java", "tests/src/**/*.kt"],
+    srcs: [
+        "tests/multivalentTests/src/**/*.java",
+        "tests/multivalentTests/src/**/*.kt",
+        "tests/src/**/*.java",
+        "tests/src/**/*.kt",
+    ],
 }
 
 filegroup {
@@ -44,5 +52,6 @@
         "tests/src/com/android/quickstep/TaplOverviewIconTest.java",
         "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
         "tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
-    ]
+        "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java"
+    ],
 }
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index db46508..bf198b6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -43,8 +43,14 @@
 
     <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
 
+    <!--
+    Permission required to access profiles which are otherwise hidden
+    from being visible via APIs, e.g. private profile.
+    -->
+    <uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
+
     <!-- Permission required to start a WidgetPickerActivity. -->
-    <permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
+    <permission android:name="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY"
         android:protectionLevel="signature|privileged" />
 
     <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -73,15 +79,16 @@
              android:clearTaskOnLaunch="true"
              android:stateNotNeeded="true"
              android:theme="@style/LauncherTheme"
-             android:screenOrientation="unspecified"
+             android:screenOrientation="behind"
              android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
              android:resizeableActivity="true"
              android:resumeWhilePausing="true"
+             android:enableOnBackInvokedCallback="false"
              android:taskAffinity=""/>
 
         <!-- Content provider to settings search. The autority should be same as the packageName -->
         <provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
-             android:authorities="${packageName}"
+             android:authorities="${applicationId}"
              android:grantUriPermissions="true"
              android:multiprocess="true"
              android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -93,7 +100,7 @@
 
         <!-- FileProvider used for sharing images. -->
         <provider android:name="androidx.core.content.FileProvider"
-             android:authorities="${packageName}.overview.fileprovider"
+             android:authorities="${applicationId}.overview.fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
             <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
diff --git a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
deleted file mode 100644
index 0b17a7b..0000000
--- a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.testing.DebugTestInformationHandler;
-import com.android.launcher3.testing.shared.TestProtocol;
-
-/**
- * Class to handle requests from tests, including debug ones, to Quickstep Launcher builds.
- */
-public abstract class DebugQuickstepTestInformationHandler extends QuickstepTestInformationHandler {
-
-    private final DebugTestInformationHandler mDebugTestInformationHandler;
-
-    public DebugQuickstepTestInformationHandler(Context context) {
-        super(context);
-        mDebugTestInformationHandler = new DebugTestInformationHandler(context);
-    }
-
-    @Override
-    public Bundle call(String method, String arg, @Nullable Bundle extras) {
-        Bundle response = new Bundle();
-        if (TestProtocol.REQUEST_RECREATE_TASKBAR.equals(method)) {
-            // Allow null-pointer to catch illegal states.
-            runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
-            return response;
-        }
-        response = super.call(method, arg, extras);
-        if (response != null) return response;
-        return mDebugTestInformationHandler.call(method, arg, extras);
-    }
-}
-
diff --git a/quickstep/res/color/bubblebar_drop_target_bg_color.xml b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
new file mode 100644
index 0000000..ca37c7f
--- /dev/null
+++ b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+    <item android:alpha="0.35" android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</selector>
\ No newline at end of file
diff --git a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_back_step_shape.xml b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_back_step_shape.xml
index a07aeaa..8b4127a 100644
--- a/quickstep/res/drawable-sw600dp-land/gesture_tutorial_back_step_shape.xml
+++ b/quickstep/res/drawable-sw600dp-land/gesture_tutorial_back_step_shape.xml
@@ -16,7 +16,8 @@
     android:width="84dp"
     android:height="208dp"
     android:viewportWidth="84"
-    android:viewportHeight="208">
+    android:viewportHeight="208"
+    android:autoMirrored="true">
   <path
       android:pathData="M24.53,169.2L32.09,165.56C77.7,143.55 77.7,64.45 32.09,42.35L24.53,38.71C14.55,33.95 6.06,25.56 0,14.92V193.08C6.06,182.44 14.55,174.05 24.53,169.2Z"
       android:fillColor="?attr/onSurfaceBack"/>
diff --git a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_back_step_shape.xml b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_back_step_shape.xml
index e20458e..3a11f21 100644
--- a/quickstep/res/drawable-sw720dp-land/gesture_tutorial_back_step_shape.xml
+++ b/quickstep/res/drawable-sw720dp-land/gesture_tutorial_back_step_shape.xml
@@ -16,7 +16,8 @@
     android:width="122dp"
     android:height="303dp"
     android:viewportWidth="122"
-    android:viewportHeight="303">
+    android:viewportHeight="303"
+    android:autoMirrored="true">
   <path
       android:pathData="M35.65,245.9L46.63,240.61C112.92,208.62 112.92,93.67 46.63,61.54L35.65,56.26C21.15,49.34 8.81,37.14 0,21.69V280.6C8.81,265.15 21.15,252.95 35.65,245.9Z"
       android:fillColor="?attr/onSurfaceBack"/>
diff --git a/quickstep/res/drawable/bg_bubble_bar_drop_target.xml b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
new file mode 100644
index 0000000..79e4318
--- /dev/null
+++ b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <corners android:radius="@dimen/bubblebar_drop_target_corner_radius" />
+    <solid android:color="@color/bubblebar_drop_target_bg_color" />
+    <stroke
+        android:width="1dp"
+        android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</shape>
diff --git a/quickstep/res/drawable/bg_overview_clear_all_button.xml b/quickstep/res/drawable/bg_overview_clear_all_button.xml
index f3ff6ce..143761f 100644
--- a/quickstep/res/drawable/bg_overview_clear_all_button.xml
+++ b/quickstep/res/drawable/bg_overview_clear_all_button.xml
@@ -20,7 +20,7 @@
     <item>
         <shape android:shape="rectangle"
             android:tint="?colorButtonNormal">
-            <corners android:radius="24dp" />
+            <corners android:radius="@dimen/recents_clear_all_outline_radius" />
             <solid android:color="?androidprv:attr/materialColorSurfaceBright"/>
         </shape>
     </item>
diff --git a/quickstep/res/drawable/button_taskbar_edu_colored.xml b/quickstep/res/drawable/button_taskbar_edu_colored.xml
index a94a996..104c4b2 100644
--- a/quickstep/res/drawable/button_taskbar_edu_colored.xml
+++ b/quickstep/res/drawable/button_taskbar_edu_colored.xml
@@ -20,7 +20,7 @@
         android:color="?android:attr/colorControlHighlight">
         <item>
             <shape android:shape="rectangle">
-                <corners android:radius="16dp"/>
+                <corners android:radius="28dp"/>
                 <solid android:color="@color/taskbar_edu_button_color"/>
             </shape>
         </item>
diff --git a/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml b/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
index 9389340..c217be2 100644
--- a/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
+++ b/quickstep/res/drawable/gesture_tutorial_back_step_shape.xml
@@ -16,7 +16,8 @@
     android:width="83dp"
     android:height="208dp"
     android:viewportWidth="83"
-    android:viewportHeight="208">
+    android:viewportHeight="208"
+    android:autoMirrored="true">
   <path
       android:pathData="M23.53,169.2L31.09,165.56C76.7,143.55 76.7,64.45 31.09,42.35L23.53,38.71C13.55,33.95 5.06,25.56 -1,14.92V193.08C5.06,182.44 13.55,174.05 23.53,169.2Z"
       android:fillColor="?attr/onSurfaceBack"/>
diff --git a/quickstep/res/drawable/ic_chevron_down.xml b/quickstep/res/drawable/ic_chevron_down.xml
index 77a8295..f246cbc 100644
--- a/quickstep/res/drawable/ic_chevron_down.xml
+++ b/quickstep/res/drawable/ic_chevron_down.xml
@@ -13,35 +13,22 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <target android:name="scaleGroup">
-        <aapt:attr name="android:animation">
-            <objectAnimator
-                android:duration="150"
-                android:propertyName="scaleX"
-                android:valueFrom="1"
-                android:valueTo="-1" />
-        </aapt:attr>
-    </target>
-    <aapt:attr name="android:drawable">
-        <vector
-            android:width="48dp"
-            android:height="48dp"
-            android:autoMirrored="true"
-            android:tint="?androidprv:attr/materialColorOnSurface"
-            android:viewportHeight="48"
-            android:viewportWidth="48">
-            <group
-                android:name="scaleGroup"
-                android:pivotX="24"
-                android:pivotY="24"
-                android:rotation="90">
-                <path
-                    android:fillColor="@android:color/white"
-                    android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
-            </group>
-        </vector>
-    </aapt:attr>
-</animated-vector>
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:autoMirrored="true"
+    android:tint="?androidprv:attr/materialColorOnSurface"
+    android:viewportHeight="48"
+    android:viewportWidth="48">
+    <group
+        android:name="scaleGroup"
+        android:pivotX="24"
+        android:pivotY="24"
+        android:rotation="90">
+        <path
+            android:fillColor="@android:color/white"
+            android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
+    </group>
+</vector>
diff --git a/quickstep/res/drawable/ic_save_app_pair.xml b/quickstep/res/drawable/ic_save_app_pair.xml
deleted file mode 100644
index 4a7ee1a..0000000
--- a/quickstep/res/drawable/ic_save_app_pair.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-  <path
-      android:pathData="M13.329,2.305H4.242C2.751,2.305 1.542,3.514 1.542,5.005V13.005C1.542,14.496 2.751,15.705 4.242,15.705H7.875V19.011C7.875,20.502 9.084,21.711 10.575,21.711H19.662C21.153,21.711 22.362,20.502 22.362,19.011V10.011C22.362,8.52 21.153,7.311 19.662,7.311H16.029V5.005C16.029,3.514 14.821,2.305 13.329,2.305ZM14.329,7.311V5.005C14.329,4.452 13.882,4.005 13.329,4.005H4.242C3.69,4.005 3.242,4.452 3.242,5.005V13.005C3.242,13.557 3.69,14.005 4.242,14.005H7.875V10.011C7.875,8.52 9.084,7.311 10.575,7.311H14.329ZM9.575,14.005V10.011C9.575,9.611 9.81,9.266 10.15,9.106C10.285,9.037 10.438,8.999 10.6,8.999H19.687C20.239,8.999 20.687,9.447 20.687,9.999V18.999C20.687,19.399 20.452,19.744 20.113,19.904C19.977,19.972 19.824,20.011 19.662,20.011H10.575C10.023,20.011 9.575,19.563 9.575,19.011V15.705H9.6V14.005H9.575ZM15.542,11.996V14H17.588V15H15.542V16.996H14.542V15H12.464V14H14.542V11.996H15.542Z"
-      android:fillColor="#000000"
-      android:fillType="evenOdd"/>
-</vector>
diff --git a/quickstep/res/drawable/ic_save_app_pair_left_right.xml b/quickstep/res/drawable/ic_save_app_pair_left_right.xml
new file mode 100644
index 0000000..b104f44
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair_left_right.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M8.5,4.5H3.5C2.4,4.5 1.5,5.4 1.5,6.5V18.5C1.5,19.6 2.4,20.5 3.5,20.5H8.5C9.6,20.5 10.5,19.6 10.5,18.5V6.5C10.5,5.4 9.6,4.5 8.5,4.5ZM8.5,18.5H3.5V6.5H8.5V18.5ZM14.5,6.5H19.5V13.5H21.5V6.5C21.5,5.4 20.6,4.5 19.5,4.5H14.5C13.4,4.5 12.5,5.4 12.5,6.5V18.5C12.5,19.6 13.4,20.5 14.5,20.5H15.5V18.5H14.5V6.5ZM20.5,14.5V16.5H22.5V18.5H20.5V20.5H18.5V18.5H16.5V16.5H18.5V14.5H20.5Z"
+      android:fillColor="#48473A"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/quickstep/res/drawable/ic_save_app_pair_up_down.xml b/quickstep/res/drawable/ic_save_app_pair_up_down.xml
new file mode 100644
index 0000000..86f110c
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair_up_down.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+     Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18,2L6,2C4.9,2 4,2.9 4,4L4,9C4,10.1 4.9,11 6,11L18,11C19.1,11 20,10.1 20,9L20,4C20,2.9 19.1,2 18,2ZM18,9L6,9L6,4L18,4L18,9ZM18,13L6,13C4.9,13 4,13.9 4,15L4,20C4,21.1 4.9,22 6,22L13,22L13,20L6,20L6,15L18,15L18,16L20,16L20,15C20,13.9 19.1,13 18,13ZM16,17L18,17L18,19L20,19L20,21L18,21L18,23L16,23L16,21L14,21L14,19L16,19L16,17Z"
+      android:fillColor="#48473A"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/res/drawable/icon_menu_background.xml b/quickstep/res/drawable/keyboard_quick_switch_thumbnail_background.xml
similarity index 70%
rename from res/drawable/icon_menu_background.xml
rename to quickstep/res/drawable/keyboard_quick_switch_thumbnail_background.xml
index 8a95c3e..961f5aa 100644
--- a/res/drawable/icon_menu_background.xml
+++ b/quickstep/res/drawable/keyboard_quick_switch_thumbnail_background.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
+<!-- Copyright (C) 2024 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
-</shape>
\ No newline at end of file
+    <solid android:color="@android:color/white" />
+    <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/view_carousel.xml b/quickstep/res/drawable/view_carousel.xml
new file mode 100644
index 0000000..16c8e78
--- /dev/null
+++ b/quickstep/res/drawable/view_carousel.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <group>
+    <clip-path
+        android:pathData="M0,0h24v24h-24z"/>
+    <path
+        android:pathData="M17,19H7V4H17V19ZM6,6H2V17H6V6ZM9,6H15V17H9V6ZM22,6H18V17H22V6Z"
+        android:fillColor="#ffffff"
+        android:fillType="evenOdd"/>
+  </group>
+</vector>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 69e1574..38df756 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -36,19 +36,19 @@
         app:layout_constraintEnd_toEndOf="parent">
 
         <include
-            layout="@layout/keyboard_quick_switch_thumbnail"
-            android:id="@+id/thumbnail1"
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_1"
             android:layout_width="0dp"
             android:layout_height="match_parent"
 
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintEnd_toStartOf="@id/thumbnail2"/>
+            app:layout_constraintEnd_toStartOf="@id/thumbnail_2"/>
 
         <include
-            layout="@layout/keyboard_quick_switch_thumbnail"
-            android:id="@+id/thumbnail2"
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_2"
             android:layout_width="0dp"
             android:layout_height="match_parent"
             android:visibility="gone"
@@ -56,31 +56,33 @@
 
             app:layout_constraintTop_toTopOf="parent"
             app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintStart_toEndOf="@id/thumbnail1"
+            app:layout_constraintStart_toEndOf="@id/thumbnail_1"
             app:layout_constraintEnd_toEndOf="parent"/>
 
         <ImageView
-            android:id="@+id/icon1"
+            android:id="@+id/icon_1"
             android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
-            android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
-            android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
             android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
 
-            app:layout_constraintTop_toTopOf="@id/thumbnail1"
-            app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+            app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
 
         <ImageView
-            android:id="@+id/icon2"
+            android:id="@+id/icon_2"
             android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
-            android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
-            android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
             android:importantForAccessibility="no"
             android:visibility="gone"
+            android:scaleType="centerCrop"
 
-            app:layout_constraintTop_toTopOf="@id/thumbnail2"
-            app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+            app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 672440f..e4942ae 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -159,7 +159,7 @@
             style="@style/TextAppearance.GestureTutorial.ButtonLabel"
             android:id="@+id/gesture_tutorial_menu_done_button"
             android:layout_width="wrap_content"
-            android:layout_height="40dp"
+            android:layout_height="48dp"
             android:layout_marginVertical="16dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
diff --git a/quickstep/res/layout/bubble_bar_drop_target.xml b/quickstep/res/layout/bubble_bar_drop_target.xml
new file mode 100644
index 0000000..23f240c
--- /dev/null
+++ b/quickstep/res/layout/bubble_bar_drop_target.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/bubblebar_size"
+    android:layout_height="@dimen/bubblebar_size"
+    android:background="@drawable/bg_bubble_bar_drop_target"
+    android:elevation="@dimen/bubblebar_elevation" />
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index c8ee6e9..668a2e1 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -157,7 +157,7 @@
             style="@style/TextAppearance.GestureTutorial.ButtonLabel"
             android:id="@+id/gesture_tutorial_menu_done_button"
             android:layout_width="wrap_content"
-            android:layout_height="40dp"
+            android:layout_height="48dp"
             android:layout_marginVertical="16dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
index b7acb70..fb9bf99 100644
--- a/quickstep/res/layout/icon_app_chip_view.xml
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -17,45 +17,41 @@
 <com.android.quickstep.views.IconAppChipView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/icon"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
+    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:importantForAccessibility="no"
     android:autoMirrored="true"
-    android:background="@drawable/icon_menu_elevation_background"
-    android:elevation="@dimen/task_thumbnail_icon_menu_elevation" >
+    android:elevation="@dimen/task_thumbnail_icon_menu_elevation"
+    android:background="?androidprv:attr/materialColorSurfaceBright">
 
-    <ImageView
-        android:id="@+id/icon_view_background_corners_start"
-        android:layout_width="@dimen/task_thumbnail_icon_menu_corner_width"
-        android:layout_height="@dimen/task_thumbnail_icon_menu_min_height"
-        android:src="@drawable/icon_menu_background_corners"
-        android:importantForAccessibility="no" />
-    <ImageView
-        android:id="@+id/icon_view_background"
-        android:layout_width="@dimen/task_thumbnail_icon_menu_background_min_width"
-        android:layout_height="@dimen/task_thumbnail_icon_menu_min_height"
-        android:src="@drawable/icon_menu_background"
-        android:importantForAccessibility="no" />
-    <ImageView
-        android:id="@+id/icon_view_background_corners_end"
-        android:layout_width="@dimen/task_thumbnail_icon_menu_corner_width"
-        android:layout_height="@dimen/task_thumbnail_icon_menu_min_height"
-        android:src="@drawable/icon_menu_background_corners"
-        android:importantForAccessibility="no" />
+    <!-- ignoring warning because the user of the anchor is a Rect where RTL is not needed -->
+    <!-- This anchor's bounds is in the expected location after rotations and translations are
+    applied to the parent. The same is not true of the parent so an anchor is used. -->
+    <!-- marginTop is applied in java to get the gap between chip and menu -->
+    <View
+        android:id="@+id/icon_view_menu_anchor"
+        android:layout_width="0dp"
+        android:layout_height="0dp"
+        android:layout_gravity="left|top"
+        android:focusable="false"
+        android:importantForAccessibility="no"
+        tools:ignore="RtlHardcoded" />
 
     <com.android.quickstep.views.IconView
         android:id="@+id/icon_view"
-        android:layout_width="@dimen/task_thumbnail_icon_size"
-        android:layout_height="@dimen/task_thumbnail_icon_size"
+        android:layout_width="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
+        android:layout_height="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
         android:focusable="false"
         android:importantForAccessibility="no" />
 
     <TextView
         android:id="@+id/icon_text_collapsed"
-        android:layout_width="@dimen/task_thumbnail_icon_menu_text_width"
-        android:layout_height="@dimen/task_thumbnail_icon_menu_drawable_size"
+        android:layout_width="@dimen/task_thumbnail_icon_menu_text_collapsed_max_width"
+        android:layout_height="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
         android:gravity="start|center_vertical"
         android:maxLines="1"
         android:ellipsize="end"
@@ -65,8 +61,8 @@
 
     <TextView
         android:id="@+id/icon_text_expanded"
-        android:layout_width="@dimen/task_thumbnail_icon_menu_text_max_width"
-        android:layout_height="@dimen/task_thumbnail_icon_menu_drawable_size"
+        android:layout_width="@dimen/task_thumbnail_icon_menu_text_expanded_max_width"
+        android:layout_height="@dimen/task_thumbnail_icon_menu_app_icon_collapsed_size"
         android:gravity="start|center_vertical"
         android:maxLines="1"
         android:ellipsize="end"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 6ed3c6e..c0ace9a 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -36,51 +36,53 @@
         app:layout_constraintEnd_toEndOf="parent">
 
         <include
-            layout="@layout/keyboard_quick_switch_thumbnail"
-            android:id="@+id/thumbnail1"
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_1"
             android:layout_width="match_parent"
             android:layout_height="0dp"
 
             app:layout_constraintTop_toTopOf="parent"
-            app:layout_constraintBottom_toTopOf="@id/thumbnail2"
+            app:layout_constraintBottom_toTopOf="@id/thumbnail_2"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toEndOf="parent"/>
 
         <include
-            layout="@layout/keyboard_quick_switch_thumbnail"
-            android:id="@+id/thumbnail2"
+            layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+            android:id="@+id/thumbnail_2"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:visibility="gone"
             android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
 
-            app:layout_constraintTop_toBottomOf="@id/thumbnail1"
+            app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toEndOf="parent"/>
 
         <ImageView
-            android:id="@+id/icon1"
+            android:id="@+id/icon_1"
             android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
-            android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
-            android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
             android:importantForAccessibility="no"
+            android:scaleType="centerCrop"
 
-            app:layout_constraintTop_toTopOf="@id/thumbnail1"
-            app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+            app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
 
         <ImageView
-            android:id="@+id/icon2"
+            android:id="@+id/icon_2"
             android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
-            android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
-            android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
             android:importantForAccessibility="no"
             android:visibility="gone"
+            android:scaleType="centerCrop"
 
-            app:layout_constraintTop_toTopOf="@id/thumbnail2"
-            app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+            app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+            app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+            app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+            app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
diff --git a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_thumbnail.xml
similarity index 92%
rename from quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
rename to quickstep/res/layout/keyboard_quick_switch_taskview_thumbnail.xml
index dde9cac..8cd8560 100644
--- a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_thumbnail.xml
@@ -18,6 +18,6 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:scaleType="centerCrop"
-    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:background="@drawable/keyboard_quick_switch_thumbnail_background"
     android:clipToOutline="true"
     android:importantForAccessibility="no"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
similarity index 97%
rename from quickstep/res/layout/keyboard_quick_switch_overview.xml
rename to quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
index 4a9b023..e48794e 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_textonly_taskview.xml
@@ -40,7 +40,6 @@
             android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
             android:layout_marginBottom="8dp"
-            android:src="@drawable/ic_empty_recents"
             android:tint="?androidprv:attr/materialColorOnSurface"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 5af8d51..2bba788 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -42,8 +42,8 @@
             android:layout_width="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
             android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
-            android:src="@drawable/ic_empty_recents"
-            android:tint="?androidprv:attr/materialColorOnSurfaceInverse"
+            android:src="@drawable/view_carousel"
+            android:tint="?androidprv:attr/materialColorOnSurface"
             android:importantForAccessibility="no"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 0fda0bf..d086da4 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -21,16 +21,11 @@
 
     <LinearLayout
         android:id="@+id/action_buttons"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="@dimen/overview_actions_height"
         android:layout_gravity="bottom|center_horizontal"
         android:orientation="horizontal">
 
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1" />
-
         <Button
             android:id="@+id/action_screenshot"
             style="@style/OverviewActionButton"
@@ -40,31 +35,23 @@
             android:text="@string/action_screenshot"
             android:theme="@style/ThemeControlHighlightWorkspaceColor" />
 
-        <Space
-            android:id="@+id/action_split_space"
-            android:layout_width="@dimen/overview_actions_button_spacing"
-            android:layout_height="1dp"
-            android:visibility="gone" />
-
         <Button
             android:id="@+id/action_split"
             style="@style/OverviewActionButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/overview_actions_button_spacing"
             android:text="@string/action_split"
             android:theme="@style/ThemeControlHighlightWorkspaceColor"
             android:visibility="gone" />
 
-        <Space
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1" />
-
-        <Space
-            android:id="@+id/oav_three_button_space"
-            android:layout_width="0dp"
-            android:layout_height="1dp"
-            android:layout_weight="1"
+        <Button
+            android:id="@+id/action_save_app_pair"
+            style="@style/OverviewActionButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/action_save_app_pair"
+            android:theme="@style/ThemeControlHighlightWorkspaceColor"
             android:visibility="gone" />
     </LinearLayout>
 
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index da94c3a..3380ea4 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -17,10 +17,12 @@
 <com.android.quickstep.views.ClearAllButton
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     style="@style/OverviewClearAllButton"
     android:id="@+id/clear_all"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/recents_clear_all"
     android:textColor="?androidprv:attr/materialColorOnSurface"
+    launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
     android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 0bbbfd5..1115ff2 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -24,8 +24,7 @@
     android:paddingTop="@dimen/split_instructions_vertical_padding"
     android:paddingBottom="@dimen/split_instructions_vertical_padding"
     android:elevation="@dimen/split_instructions_elevation"
-    android:visibility="gone"
-    android:importantForAccessibility="yes">
+    android:visibility="gone">
     <androidx.appcompat.widget.AppCompatTextView
         android:id="@+id/split_instructions_text"
         android:layout_height="wrap_content"
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 823a86e..9d599c9 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/task"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 60827cd..3cafcfd 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/task"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="true"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index d20afd3..e91e773 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -24,6 +24,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/task"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
diff --git a/quickstep/res/layout/task_menu.xml b/quickstep/res/layout/task_menu.xml
index 622edfe..b6d8786 100644
--- a/quickstep/res/layout/task_menu.xml
+++ b/quickstep/res/layout/task_menu.xml
@@ -35,11 +35,17 @@
         android:paddingBottom="@dimen/task_menu_edge_padding"
         android:textSize="16sp"/>
 
-    <LinearLayout
-        android:id="@+id/menu_option_layout"
+    <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:showDividers="middle" />
+        android:layout_height="wrap_content">
+
+        <LinearLayout
+            android:id="@+id/menu_option_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:showDividers="middle" />
+
+    </ScrollView>
 
 </com.android.quickstep.views.TaskMenuView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml
index 38573fd..c9108a5 100644
--- a/quickstep/res/layout/task_menu_with_arrow.xml
+++ b/quickstep/res/layout/task_menu_with_arrow.xml
@@ -23,11 +23,17 @@
     android:orientation="vertical"
     android:visibility="invisible">
 
-    <LinearLayout
-        android:id="@+id/menu_option_layout"
+    <ScrollView
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:showDividers="middle" />
+        android:layout_height="wrap_content">
+
+        <LinearLayout
+            android:id="@+id/menu_option_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:showDividers="middle" />
+
+    </ScrollView>
 
 </com.android.quickstep.views.TaskMenuViewWithArrow>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 30ab4b1..ffe2401 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -41,6 +41,8 @@
         android:layout_marginStart="@dimen/task_menu_option_text_start_margin"
         android:textSize="14sp"
         android:textColor="?androidprv:attr/materialColorOnSurface"
-        android:focusable="false" />
+        android:focusable="false"
+        android:gravity="start"
+        android:ellipsize="end" />
 
 </LinearLayout>
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index 72d7485..736706a 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -35,7 +35,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 
-    <FrameLayout
+    <com.android.launcher3.taskbar.navbutton.NearestTouchFrame
         android:id="@+id/navbuttons_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -62,7 +62,7 @@
             android:layout_height="match_parent"
             android:gravity="center_vertical"
             android:layout_gravity="end"/>
-    </FrameLayout>
+    </com.android.launcher3.taskbar.navbutton.NearestTouchFrame>
 
     <com.android.launcher3.taskbar.StashedHandleView
         android:id="@+id/stashed_handle"
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index c50db2e..94596cb 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,10 +14,9 @@
 -->
 
 <!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
-<com.android.launcher3.views.IconButtonView
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/BaseIcon.Workspace.Taskbar"
     android:layout_width="@dimen/taskbar_icon_min_touch_size"
     android:layout_height="@dimen/taskbar_icon_min_touch_size"
-    android:contentDescription="@string/all_apps_button_label"
     android:backgroundTint="@android:color/transparent"
-    />
+    android:contentDescription="@string/all_apps_button_label" />
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 0a92fa9..330f85f 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2023 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,9 +12,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.views.IconButtonView
-    xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/BaseIcon.Workspace.Taskbar"
     android:layout_width="@dimen/taskbar_icon_min_touch_size"
     android:layout_height="@dimen/taskbar_icon_min_touch_size"
-    android:contentDescription="@string/taskbar_divider_a11y_title"
-    android:backgroundTint="@android:color/transparent" />
\ No newline at end of file
+    android:backgroundTint="@android:color/transparent"
+    android:contentDescription="@string/taskbar_divider_a11y_title" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_edu_circle_to_search.xml b/quickstep/res/layout/taskbar_edu_circle_to_search.xml
new file mode 100644
index 0000000..6c95f25
--- /dev/null
+++ b/quickstep/res/layout/taskbar_edu_circle_to_search.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/title"
+        style="@style/TextAppearance.TaskbarEduTooltip.Title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:text="@string/taskbar_edu_circle_to_search_title"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@+id/circle_to_search_animation" />
+
+    <com.airbnb.lottie.LottieAnimationView
+        android:id="@+id/circle_to_search_animation"
+        android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
+        android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
+        android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
+        app:layout_constraintBottom_toTopOf="@id/circle_to_search_text"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/title"
+        app:lottie_rawRes="@raw/taskbar_edu_circle_to_search"
+        app:lottie_autoPlay="true"
+        app:lottie_loop="true" />
+
+    <TextView
+        android:id="@+id/circle_to_search_text"
+        style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:textSize="@dimen/taskbar_edu_circle_to_search_subtitle_text_size"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/circle_to_search_animation"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/taskbar_edu_features.xml b/quickstep/res/layout/taskbar_edu_features.xml
index 15de74c..a7bd184 100644
--- a/quickstep/res/layout/taskbar_edu_features.xml
+++ b/quickstep/res/layout/taskbar_edu_features.xml
@@ -122,7 +122,8 @@
         style="@style/TaskbarEdu.Button.Done"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="32dp"
+        android:layout_marginTop="20dp"
+        android:paddingVertical="12dp"
         android:text="@string/taskbar_edu_done"
         android:textColor="?androidprv:attr/textColorOnAccent"
 
diff --git a/quickstep/res/layout/taskbar_edu_pinning.xml b/quickstep/res/layout/taskbar_edu_pinning.xml
new file mode 100644
index 0000000..27a7b23
--- /dev/null
+++ b/quickstep/res/layout/taskbar_edu_pinning.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <TextView
+        android:id="@+id/title"
+        style="@style/TextAppearance.TaskbarEduTooltip.Title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:text="@string/taskbar_edu_pinning_title"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@+id/standalone_pinning_animation" />
+
+    <com.airbnb.lottie.LottieAnimationView
+        android:id="@+id/standalone_pinning_animation"
+        android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
+        android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
+        android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
+        app:layout_constraintBottom_toTopOf="@id/pinning_text"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/title"
+        app:lottie_rawRes="@raw/taskbar_edu_pinning"
+        app:lottie_autoPlay="true"
+        app:lottie_loop="true" />
+
+    <TextView
+        android:id="@+id/pinning_text"
+        style="@style/TextAppearance.TaskbarEduTooltip.Subtext"
+        android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:text="@string/taskbar_edu_pinning_standalone"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/standalone_pinning_animation"
+        app:layout_constraintBottom_toBottomOf="parent" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
+
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 0890a4e..7c55bf8 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -41,9 +41,10 @@
     <com.android.launcher3.taskbar.bubbles.BubbleBarView
         android:id="@+id/taskbar_bubbles"
         android:layout_width="wrap_content"
-        android:layout_height="@dimen/bubblebar_size"
+        android:layout_height="@dimen/bubblebar_size_with_pointer"
         android:layout_gravity="bottom|end"
-        android:layout_marginEnd="@dimen/transient_taskbar_bottom_margin"
+        android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
+        android:paddingTop="@dimen/bubblebar_pointer_visible_size"
         android:paddingEnd="@dimen/taskbar_icon_spacing"
         android:paddingStart="@dimen/taskbar_icon_spacing"
         android:visibility="gone"
@@ -52,7 +53,7 @@
         android:elevation="@dimen/bubblebar_elevation"
         />
 
-    <FrameLayout
+    <com.android.launcher3.taskbar.navbutton.NearestTouchFrame
         android:id="@+id/navbuttons_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -83,7 +84,7 @@
             android:paddingTop="@dimen/taskbar_contextual_padding_top"
             android:gravity="center_vertical"
             android:layout_gravity="end"/>
-    </FrameLayout>
+    </com.android.launcher3.taskbar.navbutton.NearestTouchFrame>
 
     <com.android.launcher3.taskbar.StashedHandleView
         android:id="@+id/stashed_handle"
diff --git a/quickstep/res/raw/taskbar_edu_circle_to_search.json b/quickstep/res/raw/taskbar_edu_circle_to_search.json
new file mode 100644
index 0000000..0dcccd6
--- /dev/null
+++ b/quickstep/res/raw/taskbar_edu_circle_to_search.json
@@ -0,0 +1 @@
+{"v":"5.12.1","fr":60,"ip":0,"op":431,"w":348,"h":218,"nm":"Omni_EDU_05_matted","ddd":0,"assets":[{"id":"comp_0","nm":"Omni_EDU_05","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".black","cl":"black","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-140,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,-48,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":174,"s":[0,0]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":192,"s":[17,17]},{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":237,"s":[17,17]},{"t":249,"s":[0,0]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-48],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":174,"op":249,"st":40,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"c2s null","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":193,"s":[-56.933,-189.286,0],"to":[-0.023,-0.021,0],"ti":[0.092,0.088,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":194,"s":[-57.069,-189.414,0],"to":[-0.092,-0.088,0],"ti":[0.189,0.184,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":195,"s":[-57.488,-189.813,0],"to":[-0.189,-0.184,0],"ti":[0.29,0.293,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":196,"s":[-58.204,-190.519,0],"to":[-0.29,-0.293,0],"ti":[0.392,0.419,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":197,"s":[-59.226,-191.574,0],"to":[-0.392,-0.419,0],"ti":[0.492,0.566,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":198,"s":[-60.555,-193.035,0],"to":[-0.492,-0.566,0],"ti":[0.582,0.741,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":199,"s":[-62.177,-194.971,0],"to":[-0.582,-0.741,0],"ti":[0.641,0.957,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":200,"s":[-64.048,-197.48,0],"to":[-0.641,-0.957,0],"ti":[0.644,1.22,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":201,"s":[-66.021,-200.712,0],"to":[-0.644,-1.22,0],"ti":[0.59,1.52,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":202,"s":[-67.912,-204.803,0],"to":[-0.59,-1.52,0],"ti":[0.478,1.841,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":203,"s":[-69.561,-209.83,0],"to":[-0.478,-1.841,0],"ti":[0.309,2.174,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":204,"s":[-70.781,-215.849,0],"to":[-0.309,-2.174,0],"ti":[0.095,2.509,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":205,"s":[-71.414,-222.876,0],"to":[-0.095,-2.509,0],"ti":[-0.149,2.838,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":206,"s":[-71.348,-230.903,0],"to":[0.149,-2.838,0],"ti":[-0.493,3.137,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":207,"s":[-70.519,-239.902,0],"to":[0.493,-3.137,0],"ti":[-0.971,3.37,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":208,"s":[-68.392,-249.724,0],"to":[0.971,-3.37,0],"ti":[-1.521,3.501,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":209,"s":[-64.693,-260.12,0],"to":[1.521,-3.501,0],"ti":[-2.183,3.438,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":210,"s":[-59.267,-270.731,0],"to":[2.183,-3.438,0],"ti":[-3.014,2.996,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":211,"s":[-51.596,-280.747,0],"to":[3.014,-2.996,0],"ti":[-3.718,2.327,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":212,"s":[-41.184,-288.709,0],"to":[3.718,-2.327,0],"ti":[-4.093,1.634,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":213,"s":[-29.289,-294.708,0],"to":[4.093,-1.634,0],"ti":[-4.243,0.814,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":214,"s":[-16.628,-298.511,0],"to":[4.243,-0.814,0],"ti":[-4.168,-0.028,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":215,"s":[-3.828,-299.591,0],"to":[4.168,0.028,0],"ti":[-3.907,-0.628,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":216,"s":[8.377,-298.344,0],"to":[3.907,0.628,0],"ti":[-3.551,-1.009,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":217,"s":[19.614,-295.822,0],"to":[3.551,1.009,0],"ti":[-3.138,-1.314,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":218,"s":[29.681,-292.288,0],"to":[3.138,1.314,0],"ti":[-2.68,-1.566,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":219,"s":[38.443,-287.941,0],"to":[2.68,1.566,0],"ti":[-2.137,-1.816,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":220,"s":[45.761,-282.889,0],"to":[2.137,1.816,0],"ti":[-1.616,-1.954,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":221,"s":[51.267,-277.046,0],"to":[1.616,1.954,0],"ti":[-1.251,-1.903,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":222,"s":[55.456,-271.165,0],"to":[1.251,1.903,0],"ti":[-0.99,-1.774,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":223,"s":[58.77,-265.626,0],"to":[0.99,1.774,0],"ti":[-0.752,-1.637,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":224,"s":[61.394,-260.52,0],"to":[0.752,1.637,0],"ti":[-0.54,-1.496,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":225,"s":[63.282,-255.805,0],"to":[0.54,1.496,0],"ti":[-0.388,-1.34,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":226,"s":[64.634,-251.545,0],"to":[0.388,1.34,0],"ti":[-0.278,-1.183,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":227,"s":[65.61,-247.762,0],"to":[0.278,1.183,0],"ti":[-0.195,-1.031,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":228,"s":[66.303,-244.447,0],"to":[0.195,1.031,0],"ti":[-0.13,-0.885,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":229,"s":[66.778,-241.579,0],"to":[0.13,0.885,0],"ti":[-0.081,-0.748,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":230,"s":[67.085,-239.135,0],"to":[0.081,0.748,0],"ti":[-0.045,-0.619,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":231,"s":[67.265,-237.089,0],"to":[0.045,0.619,0],"ti":[-0.02,-0.498,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":232,"s":[67.354,-235.418,0],"to":[0.02,0.498,0],"ti":[-0.004,-0.385,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":233,"s":[67.382,-234.099,0],"to":[0.004,0.385,0],"ti":[0.004,-0.279,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":234,"s":[67.377,-233.109,0],"to":[-0.004,0.279,0],"ti":[0.006,-0.18,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":235,"s":[67.358,-232.425,0],"to":[-0.006,0.18,0],"ti":[0.004,-0.087,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":236,"s":[67.341,-232.028,0],"to":[-0.004,0.087,0],"ti":[0.001,-0.021,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":237,"s":[67.335,-231.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":248,"s":[67.335,-231.9,0],"to":[-0.008,0.042,0],"ti":[0.033,-0.177,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":249,"s":[67.289,-231.647,0],"to":[-0.033,0.177,0],"ti":[0.079,-0.372,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":250,"s":[67.135,-230.84,0],"to":[-0.079,0.372,0],"ti":[0.155,-0.591,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":251,"s":[66.815,-229.413,0],"to":[-0.155,0.591,0],"ti":[0.268,-0.834,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":252,"s":[66.203,-227.297,0],"to":[-0.268,0.834,0],"ti":[0.413,-1.109,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":253,"s":[65.206,-224.409,0],"to":[-0.413,1.109,0],"ti":[0.247,-0.628,0]},{"t":254,"s":[63.723,-220.641,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":193,"op":264,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":90,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.149,"y":0.701},"o":{"x":0.4,"y":0.002},"t":248,"s":[-8.212,-253.668,0],"to":[0,0,0],"ti":[0,0,0]},{"t":263,"s":[0,-227,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.149,"y":0.701},"o":{"x":0.4,"y":0.002},"t":248,"s":[{"i":[[3.564,-2.549],[3.809,-1.264],[12.238,3.984],[8.325,10.606],[-0.214,12.436],[-2.655,8.03],[-10.533,8.871],[-9.434,2.582],[-8.48,-3.643],[-9.227,-13.6],[-1.802,-9.359],[2.171,-9.596]],"o":[[-3.564,2.549],[-12.609,4.183],[-12.52,-4.076],[-7.722,-9.838],[0.146,-8.454],[4.364,-13.197],[5.142,-4.331],[9.891,-2.707],[11.828,5.081],[4.099,6.042],[2.254,11.707],[-3.907,17.266]],"v":[[53.514,60.456],[41.519,66.798],[2.462,64.221],[-33.286,39.729],[-45.626,-0.393],[-41.723,-21.691],[-18.543,-58.238],[5.442,-69.196],[39.994,-68.523],[68.082,-43.976],[77.052,-19.838],[77.406,14.145]],"c":true}]},{"t":263,"s":[{"i":[[7.701,-4.092],[8.127,0],[7.226,4.357],[4.092,7.701],[0,8.127],[-4.357,7.226],[-7.701,4.092],[-8.127,0],[-7.226,-4.357],[-4.092,-7.701],[0,-8.127],[4.357,-7.226]],"o":[[-6.709,3.565],[-9.053,0],[-7.447,-4.489],[-3.565,-6.709],[0,-9.053],[4.489,-7.447],[6.709,-3.565],[9.053,0],[7.447,4.489],[3.565,6.709],[0,9.053],[-4.489,7.447]],"v":[[22.492,42.415],[0,48],[-24.747,41.137],[-42.415,22.492],[-48,0],[-41.137,-24.747],[-22.492,-42.415],[0,-48],[24.747,-41.137],[42.415,-22.492],[48,0],[41.137,24.747]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":78.63,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector 303","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.4],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":193,"s":[0]},{"t":237,"s":[63],"h":1},{"i":{"x":[0.149],"y":[0.701]},"o":{"x":[0.4],"y":[0.002]},"t":248,"s":[63]},{"t":263,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":3,"nm":"Trim Paths 2","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":193,"op":263,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":277,"s":[0]},{"t":289,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[2.625,-203,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[2.625,-221,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.5,1.3],[0,0],[0,0],[0,0],[-0.65,1.45],[-0.25,1.6],[0,0],[2.65,-2.25],[3.6,0],[2.9,2.85],[0,4.05],[-2.85,2.85],[-4.1,0],[-1.1,-0.3],[-1,-0.5],[0,0],[1.7,0.5],[1.8,0],[3.75,-3.75],[0,-5.3],[-3.75,-3.75],[-5.4,0],[-2,0.7]],"o":[[0,0],[0,0],[0,0],[1.05,-1.35],[0.7,-1.5],[0,0],[-0.7,3.35],[-2.6,2.2],[-4.1,0],[-2.85,-2.9],[0,-4.05],[2.9,-2.9],[1.2,0],[1.1,0.25],[0,0],[-1.45,-0.85],[-1.65,-0.5],[-5.35,0],[-3.75,3.75],[0,5.3],[3.75,3.75],[2.25,0],[2,-0.75]],"v":[[1.35,9.863],[21.075,29.587],[24.375,26.288],[4.575,6.637],[7.125,2.438],[8.55,-2.213],[3.975,-2.213],[-1.05,6.188],[-10.35,9.488],[-20.85,5.212],[-25.125,-5.213],[-20.85,-15.562],[-10.35,-19.913],[-6.9,-19.462],[-3.75,-18.337],[-0.45,-21.637],[-5.175,-23.663],[-10.35,-24.413],[-24,-18.788],[-29.625,-5.213],[-24,8.363],[-10.275,13.988],[-3.9,12.938]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-3.05,-3.05],[0,-4.4],[-3.05,3.05],[-4.4,0],[3.05,3.05],[0,4.4],[3.05,-3.05],[4.4,0]],"o":[[3.05,3.05],[0,-4.4],[3.05,-3.05],[-4.4,0],[-3.05,-3.05],[0,4.4],[-3.05,3.05],[4.4,0]],"v":[[9.3,-9.262],[13.875,1.913],[18.45,-9.262],[29.625,-13.837],[18.45,-18.413],[13.875,-29.587],[9.3,-18.413],[-1.875,-13.837]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[-100,-161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":180,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[100,-161,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[100,-279,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".black","cl":"black","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[-100,-279,0]}],"ix":2,"l":2},"a":{"a":0,"k":[11,11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[{"i":[[0,0],[7.26,-4.415],[4.064,-7.787],[0,-8]],"o":[[-9.118,0],[-7.478,4.547],[-3.462,6.633],[0,0]],"v":[[11,-37],[-13.903,-30.043],[-31.581,-11.176],[-37,11]],"c":false}]},{"t":290,"s":[{"i":[[0,0],[0,0],[0,-7.732],[0,0]],"o":[[0,0],[-7.732,0],[0,0],[0,0]],"v":[[11,-11],[3,-11],[-11,3],[-11,11]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Handle Top Left","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":63,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"Search","parent":12,"refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-166,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[0,-109,0]}],"ix":2,"l":2},"a":{"a":0,"k":[83,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":166,"h":45,"ip":135,"op":319,"st":135,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"Flower","parent":12,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.5,-209,0],"ix":2,"l":2},"a":{"a":0,"k":[109,115,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":219,"h":231,"ip":122,"op":431,"st":122,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".blue50","cl":"blue50","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":266,"s":[0]},{"t":278,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":263,"s":[0,-227,0],"to":[0,0,0],"ti":[0,0,0]},{"t":299,"s":[0,-220,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":263,"s":[92,92]},{"t":299,"s":[240,158]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":263,"s":[46]},{"t":299,"s":[12]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.941176470588,0.996078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":263,"op":431,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":3,"nm":"pan up","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.15,"y":1},"o":{"x":0.653,"y":0},"t":99,"s":[174,109,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":0.15},"o":{"x":0.546,"y":0.546},"t":169,"s":[174,327,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.15,"y":1},"o":{"x":0.653,"y":0},"t":357,"s":[174,327,0],"to":[0,0,0],"ti":[0,0,0]},{"t":427,"s":[174,109,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Void","np":19,"mn":"Pseudo/250958","ix":1,"en":1,"ef":[{"ty":0,"nm":"Width","mn":"Pseudo/250958-0001","ix":1,"v":{"a":0,"k":100,"ix":1}},{"ty":0,"nm":"Height","mn":"Pseudo/250958-0002","ix":2,"v":{"a":0,"k":100,"ix":2}},{"ty":0,"nm":"Offset X","mn":"Pseudo/250958-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Offset Y","mn":"Pseudo/250958-0004","ix":4,"v":{"a":0,"k":0,"ix":4}},{"ty":0,"nm":"Roundness","mn":"Pseudo/250958-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":6,"nm":"About","mn":"Pseudo/250958-0006","ix":6,"v":0},{"ty":6,"nm":"Plague of null layers.","mn":"Pseudo/250958-0007","ix":7,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0008","ix":8,"v":0},{"ty":6,"nm":"Following projects","mn":"Pseudo/250958-0009","ix":9,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0010","ix":10,"v":0},{"ty":6,"nm":"through time.","mn":"Pseudo/250958-0011","ix":11,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0012","ix":12,"v":0},{"ty":6,"nm":"Be free of the past.","mn":"Pseudo/250958-0013","ix":13,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0014","ix":14,"v":0},{"ty":6,"nm":"Copyright 2023 Battle Axe Inc","mn":"Pseudo/250958-0015","ix":15,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0016","ix":16,"v":0},{"ty":6,"nm":"Void","mn":"Pseudo/250958-0017","ix":17,"v":0}]}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"long Press Over - Outward","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":95,"s":[100]},{"t":113,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0.7]},"t":83,"s":[116,116]},{"t":113,"s":[136,136]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Long Pres Over","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":83,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"long Press Over","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":86,"s":[100]},{"t":95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.001,0.001],"y":[0,0]},"t":33,"s":[40,40]},{"i":{"x":[0.8,0.8],"y":[0.15,0.15]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":83,"s":[120,120]},{"t":101,"s":[40,40]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Long Pres Over","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":0,"nm":"Action Key","parent":12,"refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-11.539,38,0],"ix":2,"l":2},"a":{"a":0,"k":[53.5,53.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":107,"h":107,"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"long Press Under","parent":12,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":42,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[100]},{"t":95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":30,"s":[96,96]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":66,"s":[120,120]},{"i":{"x":[0.999,0.999],"y":[1,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":83,"s":[120,120]},{"t":101,"s":[106,106]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Long Press Under","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":30,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".grey800","cl":"grey800","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,38,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,142],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Grey800","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,218],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":431,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"SearchPill","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"superG","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[-3.898,0.128,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-4.239,0.128,0],"t":1,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-5.311,0.128,0],"t":2,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-7.286,0.128,0],"t":3,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-10.519,0.128,0],"t":4,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-15.81,0.128,0],"t":5,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-25.898,0.128,0],"t":6,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-37.431,0.128,0],"t":7,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-43.055,0.128,0],"t":8,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-46.404,0.128,0],"t":9,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-48.712,0.128,0],"t":10,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-50.434,0.128,0],"t":11,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-51.781,0.128,0],"t":12,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.869,0.128,0],"t":13,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.768,0.128,0],"t":14,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.522,0.128,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.162,0.128,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.71,0.128,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.182,0.128,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.591,0.128,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.947,0.128,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.257,0.128,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.526,0.128,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.761,0.128,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.965,0.128,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.142,0.128,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.295,0.128,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.425,0.128,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.537,0.128,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.63,0.128,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.707,0.128,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.769,0.128,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.818,0.128,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.854,0.128,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.853,0.128,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.679,0.128,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-58.301,0.128,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.701,0.128,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-57.039,0.128,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-56.46,0.128,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.983,0.128,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.588,0.128,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-55.255,0.128,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.97,0.128,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.723,0.128,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.507,0.128,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.316,0.128,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-54.147,0.128,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.996,0.128,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.861,0.128,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.74,0.128,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.631,0.128,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.534,0.128,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.446,0.128,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.367,0.128,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.297,0.128,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.234,0.128,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.178,0.128,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.128,0.128,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.084,0.128,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.046,0.128,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-53.012,0.128,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.96,0.128,0],"t":158,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[-52.913,0.128,0],"t":161,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[24.102,22.628,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.788,0],[0.959,-2.878],[0,0],[-4.737,0],[-2.091,-1.959]],"o":[[-1.262,-1.202],[-3.161,0],[0,0],[1.99,-3.959],[3.272,0],[0,0]],"v":[[6.004,1.712],[1.358,-0.106],[-5.439,4.903],[-9.458,1.783],[1.358,-4.903],[9.458,-1.742]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917647063732,0.262745112181,0.207843139768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[23.001,15.411],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-red","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.808],[-0.252,-0.727],[0,0],[0,1.959],[-0.828,1.636],[0,0],[0,0]],"o":[[0,0.808],[0,0],[-0.828,-1.636],[0,-1.959],[0,0],[0,0],[-0.242,0.727]],"v":[[2.277,0],[2.661,2.313],[-1.358,5.434],[-2.661,0],[-1.358,-5.434],[2.661,-5.434],[2.661,-2.313]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470589638,0.670588254929,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[14.901,22.628],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-yellow","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.272,0],[1.99,3.959],[0,0],[0,0],[-3.161,0],[-1.091,0.727]],"o":[[-2,1.848],[-4.737,0],[0,0],[0,0],[0.959,2.878],[1.636,0],[0,0]],"v":[[9.413,1.964],[1.404,4.903],[-9.413,-1.783],[-9.413,-4.903],[-5.393,-4.903],[1.404,0.106],[5.514,-1.066]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.203921571374,0.658823549747,0.32549020648,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[22.955,29.844],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-green","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.798],[2.283,-2.111],[0,0],[0,0],[-0.293,1.495],[0,0],[0,0]],"o":[[0.121,0.737],[0,3.686],[0,0],[0,0],[1.273,-0.858],[0,0],[0,0],[0,0]],"v":[[5.61,-5.6],[5.802,-3.308],[2.207,5.6],[-1.692,5.6],[-1.692,2.57],[0.732,-1.045],[-5.802,-1.045],[-5.802,-5.6]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258823543787,0.521568655968,0.956862747669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[30.161,26.208],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"g-blue","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"mic","parent":3,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":11,"s":[0]},{"t":17,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"k":[{"s":[2.7,0.705,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[3.041,0.705,0],"t":1,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[4.113,0.705,0],"t":2,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[6.088,0.705,0],"t":3,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[9.321,0.705,0],"t":4,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[14.611,0.705,0],"t":5,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[24.7,0.705,0],"t":6,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[36.233,0.705,0],"t":7,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[41.857,0.705,0],"t":8,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[45.206,0.705,0],"t":9,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[47.514,0.705,0],"t":10,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[49.235,0.705,0],"t":11,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[50.583,0.705,0],"t":12,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.671,0.705,0],"t":13,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.569,0.705,0],"t":14,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.323,0.705,0],"t":15,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.963,0.705,0],"t":16,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.511,0.705,0],"t":17,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.984,0.705,0],"t":18,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.393,0.705,0],"t":19,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.749,0.705,0],"t":20,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.058,0.705,0],"t":21,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.328,0.705,0],"t":22,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.563,0.705,0],"t":23,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.767,0.705,0],"t":24,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.944,0.705,0],"t":25,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.096,0.705,0],"t":26,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.227,0.705,0],"t":27,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.338,0.705,0],"t":28,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.431,0.705,0],"t":29,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.509,0.705,0],"t":30,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.571,0.705,0],"t":31,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.62,0.705,0],"t":32,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.656,0.705,0],"t":33,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.655,0.705,0],"t":129,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.48,0.705,0],"t":130,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[57.103,0.705,0],"t":131,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[56.503,0.705,0],"t":132,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.841,0.705,0],"t":133,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[55.262,0.705,0],"t":134,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.785,0.705,0],"t":135,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.39,0.705,0],"t":136,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[54.057,0.705,0],"t":137,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.772,0.705,0],"t":138,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.525,0.705,0],"t":139,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.309,0.705,0],"t":140,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[53.118,0.705,0],"t":141,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.949,0.705,0],"t":142,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.798,0.705,0],"t":143,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.663,0.705,0],"t":144,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.542,0.705,0],"t":145,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.433,0.705,0],"t":146,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.335,0.705,0],"t":147,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.248,0.705,0],"t":148,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.169,0.705,0],"t":149,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.098,0.705,0],"t":150,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[52.035,0.705,0],"t":151,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.979,0.705,0],"t":152,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.929,0.705,0],"t":153,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.886,0.705,0],"t":154,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.847,0.705,0],"t":155,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.814,0.705,0],"t":156,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.786,0.705,0],"t":157,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[51.742,0.705,0],"t":159,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"a":{"a":0,"k":[140.7,23.205,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.688,0],[0,0],[0.012,3.389],[0,0],[4.735,0],[1.554,1.554]],"o":[[1.113,1.113],[0,0],[3.377,0],[0,0],[0,4.723],[-2.361,0],[0,0]],"v":[[-5.573,0.049],[-1.242,1.848],[-1.242,1.848],[4.851,-4.282],[7.298,-4.282],[-1.242,4.282],[-7.298,1.774]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.917647063732,0.262745112181,0.207843139768,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[141.954,27.475],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-red","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,2.361],[0,0],[0,0],[-1.101,-1.113],[0,0]],"o":[[0,0],[0,0],[0,1.688],[0,0],[-1.554,-1.554]],"v":[[-2.117,-3.028],[0.33,-3.028],[0.33,-3.028],[2.117,1.303],[0.392,3.028]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470589638,0.670588254929,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[134.264,26.233],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-yellow","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.224,-1.884],[-1.224,-1.884],[-1.224,1.884],[1.224,1.884]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.203921571374,0.658823549747,0.32549020648,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[140.712,33.556],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-green","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.031,0],[0,0],[0,2.031],[0,0],[-2.031,0],[0,-2.031]],"o":[[0,2.031],[0,0],[-2.031,0],[0,0],[0,-2.031],[2.031,0],[0,0]],"v":[[3.658,4.282],[0,7.953],[0,7.953],[-3.671,4.282],[-3.671,-4.282],[0,-7.953],[3.671,-4.282]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.258823543787,0.521568655968,0.956862747669,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[140.712,18.923],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mic-blue","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"t":12,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[83,22.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.8,0.8],"y":[0.15,1]},"o":{"x":[0.3,0.3],"y":[0,0]},"t":0,"s":[56,45]},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.7,0]},"t":6,"s":[100,45]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":36,"s":[166,45]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":128,"s":[166,45]},{"t":164,"s":[154,45]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":87,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Grey 800","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"Flower","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".grey700","cl":"grey700","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[109.453,193.777,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[36.517,1.481],[-36.517,1.481]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[-12.903,0.471],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[9.094,0.471],"ix":3},"nm":"Ellipse Path 2","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[5.448,5.448],"ix":2},"p":{"a":0,"k":[2.554,0.471],"ix":3},"nm":"Ellipse Path 3","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[6.588,6.588],"ix":2},"p":{"a":0,"k":[-8.927,-0.099],"ix":3},"nm":"Ellipse Path 4","mn":"ADBE Vector Shape - Ellipse","hd":false},{"d":1,"ty":"el","s":{"a":0,"k":[6.588,6.588],"ix":2},"p":{"a":0,"k":[5.118,-0.099],"ix":3},"nm":"Ellipse Path 5","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-0.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union","np":7,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[64.952,63.598,0],"ix":2,"l":2},"a":{"a":0,"k":[24.952,23.598,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[21.137,19.31],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[28.767,23.097],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 2","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.753,0],[0,1.753],[1.753,0],[0,-1.753]],"o":[[1.753,0],[0,-1.753],[-1.753,0],[0,1.753]],"v":[[0,3.174],[3.174,0],[0,-3.174],[-3.174,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[21.75,27.886],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"flower 3","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[63.114,63.125,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[1.392,1.281],[2.395,-2.283],[1.893,0.223],[0.557,-3.174],[1.726,-0.891],[-1.504,-2.896],[0.835,-1.671],[-2.951,-1.504],[-0.278,-1.782],[-3.341,0.446],[-1.392,-1.281],[-2.395,2.283],[-1.893,-0.278],[-0.557,3.174],[-1.726,0.891],[1.504,2.896],[-0.835,1.671],[2.951,1.504],[0.334,1.838],[3.341,-0.446]],"o":[[-2.45,-2.283],[-1.392,1.337],[-3.341,-0.501],[-0.334,1.838],[-2.951,1.504],[0.835,1.671],[-1.504,2.896],[1.671,0.835],[0.557,3.174],[1.949,-0.278],[2.45,2.283],[1.392,-1.281],[3.341,0.501],[0.334,-1.838],[2.951,-1.504],[-0.835,-1.671],[1.504,-2.896],[-1.726,-0.891],[-0.557,-3.174],[-1.949,0.278]],"v":[[4.316,-21.412],[-4.372,-21.412],[-9.551,-19.741],[-16.567,-14.841],[-19.797,-10.553],[-22.47,-2.59],[-22.47,2.701],[-19.797,10.664],[-16.623,14.897],[-9.606,19.797],[-4.372,21.412],[4.316,21.412],[9.551,19.797],[16.567,14.897],[19.797,10.609],[22.47,2.645],[22.47,-2.645],[19.797,-10.609],[16.567,-14.897],[9.551,-19.797]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[97.335,135.554,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[10.748,5.402]],"o":[[0,0],[-0.891,-40.374],[0,0]],"v":[[16.706,59.315],[16.706,7.288],[-16.706,-59.315]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"▽ Right Flower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.155,88.602,0],"ix":2,"l":2},"a":{"a":0,"k":[31.228,40.542,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".black","cl":"black","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[45.33,17.598,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.184,0],[0,2.184],[2.184,0],[0,-2.184]],"o":[[2.184,0],[0,-2.184],[-2.184,0],[0,2.184]],"v":[[0,3.954],[3.954,0],[0,-3.954],[-3.954,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".red400","cl":"red400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[45.024,17.515,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.167,2.283],[4.678,-6.014],[2.283,-0.223],[-5.959,-4.733],[-0.167,-2.283],[-4.678,6.014],[-2.283,0.223],[5.959,4.733]],"o":[[-0.613,-7.574],[-1.448,1.782],[-7.629,0.668],[1.838,1.448],[0.613,7.574],[1.392,-1.838],[7.629,-0.668],[-1.838,-1.448]],"v":[[11.054,-9.829],[-3.87,-14.284],[-9.718,-11.11],[-14.228,3.926],[-11.054,9.829],[3.87,14.284],[9.718,11.11],[14.228,-3.926]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".green400","cl":"green400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[22.485,51.377,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[9.244,-14.2],[-4.678,11.138],[7.407,2.729]],"o":[[7.741,4.121],[1.002,-2.951],[-5.457,-1.448]],"v":[[-14.689,4.256],[14.269,2.642],[7.586,-8.663]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".green400","cl":"green400","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[16.651,52.32,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-10.414,5.68]],"o":[[1.726,-32.355],[0,0]],"v":[[-16.651,28.763],[16.651,-28.763]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.004,158.386,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-17.306]],"o":[[34.304,21.05],[0,0]],"v":[[-23.31,-36.483],[23.31,36.483]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[55.116,132.289,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.847,-0.501],[1.281,-3.62],[-0.78,-2.172],[-3.341,-0.891],[-3.898,2.951],[-2.339,4.01],[1.114,0.501]],"o":[[-4.177,0.39],[-0.668,1.893],[1.169,3.341],[4.733,0.668],[3.731,-2.84],[-1.114,-0.501],[-5.29,-2.228]],"v":[[-5.506,-9.773],[-14.416,-3.09],[-14.361,3.147],[-7.065,9.607],[5.91,6.655],[14.931,-4.315],[11.59,-5.819]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[65.652,111.9,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.179,3.007],[0.724,0.167],[2.228,-1.392],[-0.446,-4.622],[-4.288,-3.341],[0,-0.056],[-0.724,4.901]],"o":[[-0.668,-0.39],[-2.562,-0.613],[-4.065,2.617],[0.557,5.513],[0.501,0.39],[2.172,-4.511],[0.78,-5.235]],"v":[[4.896,-14.778],[2.836,-15.613],[-4.849,-14.221],[-9.917,-1.97],[-1.731,11.284],[5.23,15.851],[9.685,1.483]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133.059,138.554,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.731,-15.203]],"o":[[-27.844,11.695],[0,0]],"v":[[19.018,-18.878],[-19.018,18.878]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[164.078,125.618,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.404,-1.726],[-2.673,2.45],[-0.334,2.005],[0.446,1.392],[4.455,0.613],[1.671,-0.835],[0.223,-0.446],[-0.39,-0.501]],"o":[[3.397,0.891],[1.281,-1.169],[0.278,-1.448],[-1.392,-4.511],[-3.564,-0.501],[-0.446,0.223],[-0.223,0.501],[3.787,5.235]],"v":[[1.642,9.094],[11.777,7.256],[14.339,2.467],[14.061,-1.876],[4.705,-9.506],[-12.057,-5.942],[-14.452,-4.661],[-13.505,-2.879]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3.824,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]},{"id":"comp_3","nm":"Action Key","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"action icon","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[67.56,56.18,0],"ix":2,"l":2},"a":{"a":0,"k":[67.56,56.18,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,3.379],[3.379,0],[0,-3.379],[-3.379,0]],"o":[[0,-3.379],[-3.379,0],[0,3.379],[3.379,0]],"v":[[6.144,0],[0,-6.144],[-6.144,0],[0,6.144]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,6.789],[-6.789,0],[0,-6.789],[6.789,0]],"o":[[0,-6.789],[6.789,0],[0,6.789],[-6.789,0]],"v":[[-12.288,0],[0,-12.288],[12.288,0],[0,12.288]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tr","p":{"a":0,"k":[-3.185,-3.229],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[-1.101,1.239],[-1.26,-1.207],[0,0],[1.215,-1.215],[1.205,1.15],[0,0]],"o":[[1.159,-1.304],[0,0],[1.241,1.189],[-1.177,1.177],[0,0],[-1.199,-1.144]],"v":[[1.548,2.22],[5.978,2.043],[14.529,10.239],[14.575,14.619],[10.291,14.669],[1.723,6.491]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100.469,100.469],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Union","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[84.621,73.217],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"mag","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[81.029,35.842],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"top R","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 3","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[47.241,69.628],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"bottom L","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24.577,24.577],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[47.241,35.841],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"top L","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Action (not dynamic)","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[53.25,53.25,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[106.5,106.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":32,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Action (not dynamic)","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1200,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,218],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":431,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Omni_EDU_05","tt":1,"tp":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109,0],"ix":2,"l":2},"a":{"a":0,"k":[174,109,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":348,"h":218,"ip":0,"op":431,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_pinning.json b/quickstep/res/raw/taskbar_edu_pinning.json
index 161300e..56bce84 100644
--- a/quickstep/res/raw/taskbar_edu_pinning.json
+++ b/quickstep/res/raw/taskbar_edu_pinning.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU2_T2P","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_NoContainer","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[148.77,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"h":1},{"t":80,"s":[100],"h":1}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":71,"s":[240]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":79.334,"s":[312]},{"i":{"x":[0.849],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":121,"s":[420]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":255,"s":[420]},{"t":277,"s":[360]}],"ix":10},"p":{"a":0,"k":[120.053,89.949,0],"ix":2,"l":2},"a":{"a":0,"k":[10.029,10.228,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.942,0],[0,1.942],[1.942,0],[0,-1.942]],"o":[[1.942,0],[0,-1.942],[-1.942,0],[0,1.942]],"v":[[0,3.517],[3.517,0],[0,-3.517],[-3.517,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"XMLID 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.067,10.197],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"center","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.762,0],[0,0],[0,0.586],[0,0],[-0.234,0.176],[0,0],[-0.352,0.645],[0,0],[0.586,0.469],[0,0],[0,0.176],[0,0.176],[0,0],[0.352,0.645],[0,0],[0.703,-0.234],[0,0],[0.293,0.117],[0,0],[0.762,0],[0,0],[0.059,-0.703],[0,0],[0.234,-0.176],[0,0],[0.352,-0.645],[0,0],[-0.586,-0.469],[0,0],[0,-0.176],[0,-0.176],[0,0],[-0.352,-0.645],[0,0],[-0.703,0.234],[0,0],[-0.293,-0.117],[0,0]],"o":[[0,0],[0.762,0],[0,0],[0.234,-0.176],[0,0],[0.703,0.234],[0,0],[0.352,-0.645],[0,0],[0,-0.176],[0,-0.176],[0,0],[0.528,-0.41],[0,0],[-0.352,-0.645],[0,0],[-0.293,-0.176],[0,0],[-0.117,-0.762],[0,0],[-0.762,0],[0,0],[-0.234,0.176],[0,0],[-0.645,-0.234],[0,0],[-0.41,0.645],[0,0],[0,0.176],[0,0.176],[0,0],[-0.528,0.41],[0,0],[0.352,0.645],[0,0],[0.234,0.176],[0,0],[0.117,0.762]],"v":[[-1.833,10.228],[1.859,10.228],[3.266,9.114],[3.559,7.18],[4.321,6.711],[6.138,7.415],[7.955,6.77],[9.831,3.546],[9.479,1.67],[7.955,0.498],[7.955,0.029],[7.955,-0.44],[9.479,-1.612],[9.831,-3.488],[8.014,-6.653],[6.197,-7.297],[4.38,-6.594],[3.559,-7.063],[3.266,-8.939],[1.801,-10.228],[-1.892,-10.228],[-3.357,-8.997],[-3.65,-7.063],[-4.412,-6.594],[-6.229,-7.356],[-7.988,-6.711],[-9.805,-3.546],[-9.453,-1.67],[-7.929,-0.498],[-7.929,-0.029],[-7.929,0.44],[-9.453,1.612],[-9.805,3.488],[-7.988,6.653],[-6.171,7.297],[-4.354,6.594],[-3.592,7.063],[-3.299,8.939]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.059,0]],"o":[[0,0]],"v":[[-1.306,8.704]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0.41,0.352],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.41,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.293],[0.059,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.176],[0,0]],"o":[[0,0],[0,0],[0,0],[-0.469,-0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.059,-0.234],[0,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.293],[0,0],[0,0]],"v":[[1.39,8.235],[-1.365,8.235],[-1.716,5.715],[-2.185,5.48],[-3.533,4.718],[-4.002,4.367],[-6.405,5.305],[-7.812,2.901],[-5.761,1.319],[-5.819,0.733],[-5.878,-0.029],[-5.819,-0.791],[-5.761,-1.377],[-7.812,-2.96],[-6.405,-5.363],[-4.002,-4.425],[-3.533,-4.777],[-2.185,-5.539],[-1.658,-5.773],[-1.306,-8.294],[1.449,-8.294],[1.801,-5.773],[2.328,-5.539],[3.676,-4.777],[4.145,-4.425],[6.548,-5.363],[7.955,-2.96],[5.904,-1.377],[5.962,-0.791],[6.021,-0.029],[5.962,0.733],[5.904,1.319],[7.955,2.901],[6.548,5.305],[4.145,4.367],[3.676,4.718],[2.328,5.48],[1.801,5.715]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-6.171,-5.773]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-1.247,-8.763]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.029,10.228],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[100],"h":1},{"t":80,"s":[0],"h":1}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":71,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":79.334,"s":[72]},{"t":121,"s":[180]}],"ix":10},"p":{"a":0,"k":[120.053,89.949,0],"ix":2,"l":2},"a":{"a":0,"k":[10.029,10.228,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.942,0],[0,1.942],[1.942,0],[0,-1.942]],"o":[[1.942,0],[0,-1.942],[-1.942,0],[0,1.942]],"v":[[0,3.517],[3.517,0],[0,-3.517],[-3.517,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"XMLID 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.067,10.197],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"center","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.762,0],[0,0],[0,0.586],[0,0],[-0.234,0.176],[0,0],[-0.352,0.645],[0,0],[0.586,0.469],[0,0],[0,0.176],[0,0.176],[0,0],[0.352,0.645],[0,0],[0.703,-0.234],[0,0],[0.293,0.117],[0,0],[0.762,0],[0,0],[0.059,-0.703],[0,0],[0.234,-0.176],[0,0],[0.352,-0.645],[0,0],[-0.586,-0.469],[0,0],[0,-0.176],[0,-0.176],[0,0],[-0.352,-0.645],[0,0],[-0.703,0.234],[0,0],[-0.293,-0.117],[0,0]],"o":[[0,0],[0.762,0],[0,0],[0.234,-0.176],[0,0],[0.703,0.234],[0,0],[0.352,-0.645],[0,0],[0,-0.176],[0,-0.176],[0,0],[0.528,-0.41],[0,0],[-0.352,-0.645],[0,0],[-0.293,-0.176],[0,0],[-0.117,-0.762],[0,0],[-0.762,0],[0,0],[-0.234,0.176],[0,0],[-0.645,-0.234],[0,0],[-0.41,0.645],[0,0],[0,0.176],[0,0.176],[0,0],[-0.528,0.41],[0,0],[0.352,0.645],[0,0],[0.234,0.176],[0,0],[0.117,0.762]],"v":[[-1.833,10.228],[1.859,10.228],[3.266,9.114],[3.559,7.18],[4.321,6.711],[6.138,7.415],[7.955,6.77],[9.831,3.546],[9.479,1.67],[7.955,0.498],[7.955,0.029],[7.955,-0.44],[9.479,-1.612],[9.831,-3.488],[8.014,-6.653],[6.197,-7.297],[4.38,-6.594],[3.559,-7.063],[3.266,-8.939],[1.801,-10.228],[-1.892,-10.228],[-3.357,-8.997],[-3.65,-7.063],[-4.412,-6.594],[-6.229,-7.356],[-7.988,-6.711],[-9.805,-3.546],[-9.453,-1.67],[-7.929,-0.498],[-7.929,-0.029],[-7.929,0.44],[-9.453,1.612],[-9.805,3.488],[-7.988,6.653],[-6.171,7.297],[-4.354,6.594],[-3.592,7.063],[-3.299,8.939]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.059,0]],"o":[[0,0]],"v":[[-1.306,8.704]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0.41,0.352],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.41,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.293],[0.059,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.176],[0,0]],"o":[[0,0],[0,0],[0,0],[-0.469,-0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.059,-0.234],[0,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.293],[0,0],[0,0]],"v":[[1.39,8.235],[-1.365,8.235],[-1.716,5.715],[-2.185,5.48],[-3.533,4.718],[-4.002,4.367],[-6.405,5.305],[-7.812,2.901],[-5.761,1.319],[-5.819,0.733],[-5.878,-0.029],[-5.819,-0.791],[-5.761,-1.377],[-7.812,-2.96],[-6.405,-5.363],[-4.002,-4.425],[-3.533,-4.777],[-2.185,-5.539],[-1.658,-5.773],[-1.306,-8.294],[1.449,-8.294],[1.801,-5.773],[2.328,-5.539],[3.676,-4.777],[4.145,-4.425],[6.548,-5.363],[7.955,-2.96],[5.904,-1.377],[5.962,-0.791],[6.021,-0.029],[5.962,0.733],[5.904,1.319],[7.955,2.901],[6.548,5.305],[4.145,4.367],[3.676,4.718],[2.328,5.48],[1.801,5.715]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-6.171,-5.773]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-1.247,-8.763]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.029,10.228],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","parent":6,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62.008,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66.008,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242.008,"s":[100]},{"t":246.005859375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[-7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":0.8},"o":{"x":0.215,"y":0.215},"t":80,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260.068359375,"s":[-7.079,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.308,0],[0,3.308],[3.308,0],[0,-3.308]],"o":[[3.308,0],[0,-3.308],[-3.308,0],[0,3.308]],"v":[[0,5.99],[5.99,0],[0,-5.99],[-5.99,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Button","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey600","cl":"grey600","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[-7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":0.8},"o":{"x":0.215,"y":0.215},"t":80,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260.068359375,"s":[-7.079,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.308,0],[0,3.308],[3.308,0],[0,-3.308]],"o":[[3.308,0],[0,-3.308],[-3.308,0],[0,3.308]],"v":[[0,5.99],[5.99,0],[0,-5.99],[-5.99,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.502,0.525,0.545,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.502,0.525,0.545,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Button","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62.008,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66.008,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242.008,"s":[100]},{"t":246.005859375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[221.082,88.938,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[30.494,16.336],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0,0,0,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0,0,0,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Toggle Channel","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[221.082,88.938,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[30.494,16.336],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Toggle Channel","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170.985,90.027,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[156.827,38.118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Settings","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Taskbar - no fade","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174.374,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":80,"s":[191.396]},{"t":105,"s":[202],"h":1},{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":260,"s":[202]},{"t":285,"s":[191.396]}],"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":80,"s":[227,33]},{"t":105,"s":[227,30],"h":1},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":260,"s":[227,30]},{"t":285,"s":[227,33]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,93.525,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":80,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-173.9,110.706],[-156.475,125.525],[156.675,125.525],[174.1,110.706],[174,-78.705]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.2,"y":0},"t":100,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-174,78.705],[-156.575,93.525],[156.575,93.525],[174,78.705],[174,-78.705]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.2,"y":0},"t":260,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-174,78.705],[-156.575,93.525],[156.575,93.525],[174,78.705],[174,-78.705]],"c":true}]},{"t":280,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-173.9,110.706],[-156.475,125.525],[156.675,125.525],[174.1,110.706],[174,-78.705]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"BG Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,218,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","tt":1,"tp":11,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":81,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":279,"s":[100]},{"t":282,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}],"markers":[{"tm":60,"cm":"","dr":0},{"tm":80,"cm":"","dr":0},{"tm":240,"cm":"","dr":0},{"tm":260,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU2_T2P","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_NoContainer","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[148.77,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"universal grey divider","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"universal grey action","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"cog 02","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[0],"h":1},{"t":80,"s":[100],"h":1}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":71,"s":[240]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":79.334,"s":[312]},{"i":{"x":[0.849],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":121,"s":[420]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":255,"s":[420]},{"t":277,"s":[360]}],"ix":10},"p":{"a":0,"k":[120.053,89.949,0],"ix":2,"l":2},"a":{"a":0,"k":[10.029,10.228,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.942,0],[0,1.942],[1.942,0],[0,-1.942]],"o":[[1.942,0],[0,-1.942],[-1.942,0],[0,1.942]],"v":[[0,3.517],[3.517,0],[0,-3.517],[-3.517,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.941176474094,0.996078431606,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"XMLID 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.067,10.197],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"center","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.762,0],[0,0],[0,0.586],[0,0],[-0.234,0.176],[0,0],[-0.352,0.645],[0,0],[0.586,0.469],[0,0],[0,0.176],[0,0.176],[0,0],[0.352,0.645],[0,0],[0.703,-0.234],[0,0],[0.293,0.117],[0,0],[0.762,0],[0,0],[0.059,-0.703],[0,0],[0.234,-0.176],[0,0],[0.352,-0.645],[0,0],[-0.586,-0.469],[0,0],[0,-0.176],[0,-0.176],[0,0],[-0.352,-0.645],[0,0],[-0.703,0.234],[0,0],[-0.293,-0.117],[0,0]],"o":[[0,0],[0.762,0],[0,0],[0.234,-0.176],[0,0],[0.703,0.234],[0,0],[0.352,-0.645],[0,0],[0,-0.176],[0,-0.176],[0,0],[0.528,-0.41],[0,0],[-0.352,-0.645],[0,0],[-0.293,-0.176],[0,0],[-0.117,-0.762],[0,0],[-0.762,0],[0,0],[-0.234,0.176],[0,0],[-0.645,-0.234],[0,0],[-0.41,0.645],[0,0],[0,0.176],[0,0.176],[0,0],[-0.528,0.41],[0,0],[0.352,0.645],[0,0],[0.234,0.176],[0,0],[0.117,0.762]],"v":[[-1.833,10.228],[1.859,10.228],[3.266,9.114],[3.559,7.18],[4.321,6.711],[6.138,7.415],[7.955,6.77],[9.831,3.546],[9.479,1.67],[7.955,0.498],[7.955,0.029],[7.955,-0.44],[9.479,-1.612],[9.831,-3.488],[8.014,-6.653],[6.197,-7.297],[4.38,-6.594],[3.559,-7.063],[3.266,-8.939],[1.801,-10.228],[-1.892,-10.228],[-3.357,-8.997],[-3.65,-7.063],[-4.412,-6.594],[-6.229,-7.356],[-7.988,-6.711],[-9.805,-3.546],[-9.453,-1.67],[-7.929,-0.498],[-7.929,-0.029],[-7.929,0.44],[-9.453,1.612],[-9.805,3.488],[-7.988,6.653],[-6.171,7.297],[-4.354,6.594],[-3.592,7.063],[-3.299,8.939]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.059,0]],"o":[[0,0]],"v":[[-1.306,8.704]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0.41,0.352],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.41,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.293],[0.059,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.176],[0,0]],"o":[[0,0],[0,0],[0,0],[-0.469,-0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.059,-0.234],[0,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.293],[0,0],[0,0]],"v":[[1.39,8.235],[-1.365,8.235],[-1.716,5.715],[-2.185,5.48],[-3.533,4.718],[-4.002,4.367],[-6.405,5.305],[-7.812,2.901],[-5.761,1.319],[-5.819,0.733],[-5.878,-0.029],[-5.819,-0.791],[-5.761,-1.377],[-7.812,-2.96],[-6.405,-5.363],[-4.002,-4.425],[-3.533,-4.777],[-2.185,-5.539],[-1.658,-5.773],[-1.306,-8.294],[1.449,-8.294],[1.801,-5.773],[2.328,-5.539],[3.676,-4.777],[4.145,-4.425],[6.548,-5.363],[7.955,-2.96],[5.904,-1.377],[5.962,-0.791],[6.021,-0.029],[5.962,0.733],[5.904,1.319],[7.955,2.901],[6.548,5.305],[4.145,4.367],[3.676,4.718],[2.328,5.48],[1.801,5.715]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-6.171,-5.773]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-1.247,-8.763]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.941176474094,0.996078431606,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.029,10.228],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"cog 01","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[100],"h":1},{"t":80,"s":[0],"h":1}],"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.8],"y":[0.15]},"o":{"x":[0.3],"y":[0]},"t":71,"s":[0]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":79.334,"s":[72]},{"t":121,"s":[180]}],"ix":10},"p":{"a":0,"k":[120.053,89.949,0],"ix":2,"l":2},"a":{"a":0,"k":[10.029,10.228,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.942,0],[0,1.942],[1.942,0],[0,-1.942]],"o":[[1.942,0],[0,-1.942],[-1.942,0],[0,1.942]],"v":[[0,3.517],[3.517,0],[0,-3.517],[-3.517,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.941176474094,0.996078431606,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"XMLID 3","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.067,10.197],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"center","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.762,0],[0,0],[0,0.586],[0,0],[-0.234,0.176],[0,0],[-0.352,0.645],[0,0],[0.586,0.469],[0,0],[0,0.176],[0,0.176],[0,0],[0.352,0.645],[0,0],[0.703,-0.234],[0,0],[0.293,0.117],[0,0],[0.762,0],[0,0],[0.059,-0.703],[0,0],[0.234,-0.176],[0,0],[0.352,-0.645],[0,0],[-0.586,-0.469],[0,0],[0,-0.176],[0,-0.176],[0,0],[-0.352,-0.645],[0,0],[-0.703,0.234],[0,0],[-0.293,-0.117],[0,0]],"o":[[0,0],[0.762,0],[0,0],[0.234,-0.176],[0,0],[0.703,0.234],[0,0],[0.352,-0.645],[0,0],[0,-0.176],[0,-0.176],[0,0],[0.528,-0.41],[0,0],[-0.352,-0.645],[0,0],[-0.293,-0.176],[0,0],[-0.117,-0.762],[0,0],[-0.762,0],[0,0],[-0.234,0.176],[0,0],[-0.645,-0.234],[0,0],[-0.41,0.645],[0,0],[0,0.176],[0,0.176],[0,0],[-0.528,0.41],[0,0],[0.352,0.645],[0,0],[0.234,0.176],[0,0],[0.117,0.762]],"v":[[-1.833,10.228],[1.859,10.228],[3.266,9.114],[3.559,7.18],[4.321,6.711],[6.138,7.415],[7.955,6.77],[9.831,3.546],[9.479,1.67],[7.955,0.498],[7.955,0.029],[7.955,-0.44],[9.479,-1.612],[9.831,-3.488],[8.014,-6.653],[6.197,-7.297],[4.38,-6.594],[3.559,-7.063],[3.266,-8.939],[1.801,-10.228],[-1.892,-10.228],[-3.357,-8.997],[-3.65,-7.063],[-4.412,-6.594],[-6.229,-7.356],[-7.988,-6.711],[-9.805,-3.546],[-9.453,-1.67],[-7.929,-0.498],[-7.929,-0.029],[-7.929,0.44],[-9.453,1.612],[-9.805,3.488],[-7.988,6.653],[-6.171,7.297],[-4.354,6.594],[-3.592,7.063],[-3.299,8.939]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.059,0]],"o":[[0,0]],"v":[[-1.306,8.704]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0.41,0.352],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.41,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.293],[0.059,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.176],[0,0]],"o":[[0,0],[0,0],[0,0],[-0.469,-0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.059,-0.234],[0,-0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,-0.293],[0,0],[0,0],[0,0],[0,0],[0,0],[0.469,0.176],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.234],[0,0.234],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.469,0.293],[0,0],[0,0]],"v":[[1.39,8.235],[-1.365,8.235],[-1.716,5.715],[-2.185,5.48],[-3.533,4.718],[-4.002,4.367],[-6.405,5.305],[-7.812,2.901],[-5.761,1.319],[-5.819,0.733],[-5.878,-0.029],[-5.819,-0.791],[-5.761,-1.377],[-7.812,-2.96],[-6.405,-5.363],[-4.002,-4.425],[-3.533,-4.777],[-2.185,-5.539],[-1.658,-5.773],[-1.306,-8.294],[1.449,-8.294],[1.801,-5.773],[2.328,-5.539],[3.676,-4.777],[4.145,-4.425],[6.548,-5.363],[7.955,-2.96],[5.904,-1.377],[5.962,-0.791],[6.021,-0.029],[5.962,0.733],[5.904,1.319],[7.955,2.901],[6.548,5.305],[4.145,4.367],[3.676,4.718],[2.328,5.48],[1.801,5.715]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-6.171,-5.773]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0,0.059]],"o":[[0,0]],"v":[[-1.247,-8.763]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803926945,0.941176474094,0.996078431606,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":7,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.029,10.228],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","parent":6,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62.008,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66.008,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242.008,"s":[100]},{"t":246.005859375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[-7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":0.8},"o":{"x":0.215,"y":0.215},"t":80,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260.068359375,"s":[-7.079,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.308,0],[0,3.308],[3.308,0],[0,-3.308]],"o":[[3.308,0],[0,-3.308],[-3.308,0],[0,3.308]],"v":[[0,5.99],[5.99,0],[0,-5.99],[-5.99,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Button","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey600","cl":"grey600","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[-7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.8,"y":0.8},"o":{"x":0.215,"y":0.215},"t":80,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[7.079,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260.068359375,"s":[-7.079,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.308,0],[0,3.308],[3.308,0],[0,-3.308]],"o":[[3.308,0],[0,-3.308],[-3.308,0],[0,3.308]],"v":[[0,5.99],[5.99,0],[0,-5.99],[-5.99,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.502,0.525,0.545,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.502,0.525,0.545,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Button","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62.008,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66.008,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242.008,"s":[100]},{"t":246.005859375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[221.082,88.938,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[30.494,16.336],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0,0,0,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0,0,0,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Toggle Channel","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[221.082,88.938,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[30.494,16.336],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":10,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Toggle Channel","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170.985,90.027,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[156.827,38.118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Settings","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":0,"nm":"Taskbar - no fade","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174.374,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":80,"s":[191.396]},{"t":105,"s":[202],"h":1},{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":260,"s":[202]},{"t":285,"s":[191.396]}],"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":80,"s":[227,33]},{"t":105,"s":[227,30],"h":1},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":260,"s":[227,30]},{"t":285,"s":[227,33]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,93.525,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":80,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-173.9,110.706],[-156.475,125.525],[156.675,125.525],[174.1,110.706],[174,-78.705]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.2,"y":0},"t":100,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-174,78.705],[-156.575,93.525],[156.575,93.525],[174,78.705],[174,-78.705]],"c":true}]},{"i":{"x":0.833,"y":1},"o":{"x":0.2,"y":0},"t":260,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-174,78.705],[-156.575,93.525],[156.575,93.525],[174,78.705],[174,-78.705]],"c":true}]},{"t":280,"s":[{"i":[[9.624,0],[0,0],[0,-8.185],[0,0],[-9.624,0],[0,0],[0,8.185],[0,0]],"o":[[0,0],[-9.624,0],[0,0],[0,8.185],[0,0],[9.624,0],[0,0],[0,-8.185]],"v":[[156.575,-93.525],[-156.575,-93.525],[-174,-78.705],[-173.9,110.706],[-156.475,125.525],[156.675,125.525],[174.1,110.706],[174,-78.705]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660.233790992859,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"BG Matte","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,218,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","tt":1,"tp":11,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":78,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":81,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":279,"s":[100]},{"t":282,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}],"markers":[{"tm":60,"cm":"","dr":0},{"tm":80,"cm":"","dr":0},{"tm":240,"cm":"","dr":0},{"tm":260,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_settings.json b/quickstep/res/raw/taskbar_edu_settings.json
deleted file mode 100644
index a724824..0000000
--- a/quickstep/res/raw/taskbar_edu_settings.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.7.8","fr":60,"ip":0,"op":301,"w":320,"h":202,"nm":"Taskbar_Persistent_EDU_2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242,"s":[100]},{"t":246,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[209,86,0],"to":[2.833,0,0],"ti":[-2.833,0,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":80,"s":[226,86,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[226,86,0],"to":[-2.833,0,0],"ti":[2.833,0,0]},{"t":260,"s":[209,86,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[11,11],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey600","cl":"grey600","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":60,"s":[209,86,0],"to":[2.833,0,0],"ti":[-2.833,0,0]},{"i":{"x":0.1,"y":0.1},"o":{"x":0.167,"y":0.167},"t":80,"s":[226,86,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.1,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[226,86,0],"to":[-2.833,0,0],"ti":[2.833,0,0]},{"t":260,"s":[209,86,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[11,11],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":62,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":66,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":242,"s":[100]},{"t":246,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[217.5,86,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[28,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[217.5,86,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[28,15],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[101.25,86,0],"ix":2,"l":2},"a":{"a":0,"k":[-43.792,-15.776,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.784,0],[0,1.783],[1.783,0],[0,-1.783]],"o":[[1.783,0],[0,-1.783],[-1.784,0],[0,1.783]],"v":[[-43.755,-12.577],[-40.526,-15.806],[-43.755,-19.035],[-46.984,-15.806]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0.053]],"o":[[0,0.053],[0,0]],"v":[[-44.937,-23.822],[-44.937,-23.822]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0.054]],"o":[[0,0.054],[0,0]],"v":[[-49.458,-21.078],[-49.458,-21.078]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[-0.431,0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0.431,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[0,-0.216],[-0.054,-0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,-0.162],[0,0]],"o":[[0,0],[0,0],[0,0],[0.431,-0.162],[0,0],[0,0],[0,0],[0,0],[0,0],[0.054,-0.215],[0,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.377,-0.269],[0,0],[0,0],[0,0],[0,0],[0,0],[-0.431,0.161],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0.215],[0,0.215],[0,0],[0,0],[0,0],[0,0],[0,0],[0.377,0.323],[0,0],[0,0]],"v":[[-45.045,-8.215],[-42.515,-8.215],[-42.138,-10.529],[-41.654,-10.744],[-40.416,-11.444],[-39.986,-11.767],[-37.779,-10.906],[-36.487,-13.112],[-38.371,-14.565],[-38.317,-15.104],[-38.263,-15.803],[-38.317,-16.503],[-38.371,-17.041],[-36.487,-18.494],[-37.779,-20.701],[-39.986,-19.84],[-40.416,-20.163],[-41.654,-20.862],[-42.138,-21.078],[-42.461,-23.392],[-44.991,-23.392],[-45.314,-21.078],[-45.798,-20.862],[-47.036,-20.163],[-47.467,-19.84],[-49.673,-20.701],[-50.965,-18.494],[-49.081,-17.041],[-49.135,-16.503],[-49.189,-15.803],[-49.135,-15.104],[-49.081,-14.565],[-50.965,-13.112],[-49.673,-10.906],[-47.467,-11.767],[-47.036,-11.444],[-45.798,-10.744],[-45.368,-10.529]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[0,0],[0.054,0]],"o":[[0.054,0],[0,0]],"v":[[-44.991,-7.784],[-44.991,-7.784]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[0.7,0],[0,0],[0.108,0.7],[0,0],[0.215,0.162],[0,0],[0.323,0.592],[0,0],[-0.484,0.376],[0,0],[0,0.161],[0,0.162],[0,0],[-0.376,0.593],[0,0],[-0.592,-0.215],[0,0],[-0.215,0.162],[0,0],[-0.7,0],[0,0],[-0.107,-0.7],[0,0],[-0.269,-0.162],[0,0],[-0.323,-0.592],[0,0],[0.484,-0.377],[0,0],[0,-0.162],[0,-0.161],[0,0],[0.323,-0.592],[0,0],[0.646,0.215],[0,0],[0.216,-0.162],[0,0]],"o":[[0,0],[-0.7,0],[0,0],[-0.269,-0.108],[0,0],[-0.646,0.215],[0,0],[-0.323,-0.592],[0,0],[0,-0.161],[0,-0.162],[0,0],[-0.538,-0.431],[0,0],[0.323,-0.592],[0,0],[0.215,-0.162],[0,0],[0.053,-0.646],[0,0],[0.699,0],[0,0],[0.269,0.108],[0,0],[0.646,-0.215],[0,0],[0.323,0.592],[0,0],[0,0.161],[0,0.161],[0,0],[0.538,0.431],[0,0],[-0.323,0.592],[0,0],[-0.215,0.161],[0,0],[0,0.538]],"v":[[-42.085,-6.385],[-45.475,-6.385],[-46.821,-7.569],[-47.09,-9.291],[-47.789,-9.722],[-49.458,-9.076],[-51.126,-9.668],[-52.795,-12.574],[-52.472,-14.296],[-51.072,-15.373],[-51.072,-15.803],[-51.072,-16.234],[-52.472,-17.31],[-52.795,-19.033],[-51.126,-21.939],[-49.512,-22.531],[-47.843,-21.831],[-47.144,-22.262],[-46.874,-24.038],[-45.529,-25.168],[-42.138,-25.168],[-40.793,-23.984],[-40.524,-22.262],[-39.77,-21.831],[-38.102,-22.477],[-36.433,-21.885],[-34.765,-18.979],[-35.088,-17.256],[-36.487,-16.18],[-36.487,-15.749],[-36.487,-15.319],[-35.088,-14.243],[-34.765,-12.52],[-36.487,-9.56],[-38.156,-8.968],[-39.824,-9.614],[-40.524,-9.183],[-40.793,-7.407]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":6,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-43.792,-15.776],"ix":2},"a":{"a":0,"k":[-43.792,-15.776],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,86,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[125,125,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[144,35],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":15,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":84,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":265,"s":[0]},{"t":270,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[225,187,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[35,35,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.719,-0.273],[0,0],[0,0],[0.812,-0.492],[0,0],[0,0],[0,0.688],[0,0],[0,0]],"o":[[0.688,0.196],[0,0],[0,0],[-0.812,0.492],[0,0],[0,0],[0,-0.812],[0,0],[0,0]],"v":[[5.906,-10.352],[6.5,-9.219],[6.5,8.812],[5.938,10.071],[4.26,9.965],[-10.993,1.159],[-11.75,0],[-10.892,-1.217],[4.852,-10.307]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854902020623,0.862745157878,0.878431432387,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":84,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":265,"s":[0]},{"t":270,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251,187,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":0,"k":[6.5,6.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854902020623,0.862745157878,0.878431432387,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":84,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":265,"s":[0]},{"t":270,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277,187,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[6,6],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":1,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".yellow400","cl":"yellow400","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":360,"st":-65,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey300","cl":"grey300","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-83,0,0],"ix":2,"l":2},"a":{"a":0,"k":[121.456,227.454,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 18","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 17","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[125.547,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 16","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 15","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 14","np":1,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[121.453,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 13","np":1,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,231.545],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 12","np":1,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,227.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 11","np":1,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.753,0],[0,-0.753],[0.753,0],[0,0.753]],"o":[[0.753,0],[0,0.753],[-0.753,0],[0,-0.753]],"v":[[0,-1.364],[1.364,0],[0,1.364],[-1.364,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[117.364,223.364],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Layer 10","np":1,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"green circle matte","parent":22,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82.955,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".green400","cl":"green400","parent":22,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":88,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":262,"s":[100]},{"t":267,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[83.068,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".green100","cl":"green100","parent":22,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":83,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":88,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":262,"s":[100]},{"t":267,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[82.955,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.807843148708,0.917647063732,0.839215695858,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.807843137255,0.917647058824,0.839215686275,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"blue circle matte 2","parent":22,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.541175991881,0.705881993911,0.972549019608,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".blue400","cl":"blue400","parent":22,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":".blue100","cl":"blue100","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-4.443,0],[0,-4.443],[4.443,0],[0,4.443]],"o":[[4.443,0],[0,4.443],[-4.443,0],[0,-4.443]],"v":[[0,-8.045],[8.045,0],[0,8.045],[-8.045,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".yellow400","cl":"yellow400","parent":22,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[29,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294118,0.788235294118,0.203921568627,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".green400","cl":"green400","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.35686275363,0.72549021244,0.454901963472,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":".red400","cl":"red400","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333337307,0.403921574354,0.360784322023,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".blue400","cl":"blue400","parent":22,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-58,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.272,0],[0,-5.272],[5.272,0],[0,5.272]],"o":[[5.272,0],[0,5.272],[-5.272,0],[0,-5.272]],"v":[[0,-9.545],[9.545,0],[0,9.545],[-9.545,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.40000000596,0.615686297417,0.964705884457,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":80,"s":[122,186.5,0],"to":[31.333,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":105,"s":[160,179,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":260,"s":[160,179,0],"to":[0,0,0],"ti":[30.299,0.107,0]},{"t":280,"s":[122,186.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":80,"s":[202,30]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":105,"s":[202,30]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":260,"s":[202,30]},{"t":280,"s":[202,30]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":30,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":11400,"st":0,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":80,"s":[160,98.001,0],"to":[0,2.667,0],"ti":[0,-2.667,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":100,"s":[160,114.001,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":260,"s":[160,114.001,0],"to":[0,-2.667,0],"ti":[0,2.667,0]},{"t":285,"s":[160,98.001,0]}],"ix":2,"l":2},"a":{"a":0,"k":[192,122.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":80,"s":[320,170]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":100,"s":[320,202]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":260,"s":[320,202]},{"t":285,"s":[320,170]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529411765,0.890196078431,0.988235294118,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[192,109.499],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":360,"st":0,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[160,100.5,0],"ix":2,"l":2},"a":{"a":0,"k":[192,122.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[320,202],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[192,123],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":360,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json b/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json
index b5f4aec..c8e3179 100644
--- a/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json
+++ b/quickstep/res/raw/taskbar_edu_splitscreen_persistent.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Persistent_EDU1_Split","ddd":0,"assets":[{"id":"comp_0","nm":"PersistentTaskbar_edu1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"gesture","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":140,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[186.05,184.8,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[209.6,201.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":70,"s":[209.6,201.9,0],"to":[0,0,0],"ti":[-8.458,24.508,0]},{"t":120,"s":[249.85,158.35,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":130,"s":[48,48,100]},{"t":140,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":141,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":138,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249.894,158.346,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":130,"s":[120,120,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":130,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".yellow400","cl":"yellow400","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.092,-0.009,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[250,250,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":130,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":140,"s":[0]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":140,"op":305,"st":140,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"t":70,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[90,90,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.158,0.158,0.158],"y":[0,0,0]},"t":70,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":140,"s":[100,100,100]},{"t":160,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.937254905701,0.764705896378,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"PersistentTaskbar_edu1","parent":13,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":113.5,"ix":3},"y":{"a":0,"k":16.5,"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":91,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":99,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":240,"s":[100]},{"t":245,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[348,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":111,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[348,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":3,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.937254905701,0.764705896378,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[348,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":111,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[348,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":3,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[0,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[-7.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[-7.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[-9,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[-9,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[0,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":0,"nm":"PersistentTaskbar_edu1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174.374,"ix":3},"y":{"a":0,"k":202,"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[{"tm":240,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Persistent_EDU1_Split","ddd":0,"assets":[{"id":"comp_0","nm":"PersistentTaskbar_edu1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"universal grey divider","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"universal grey action","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"gesture","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":140,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[186.05,184.8,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[209.6,201.9,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":70,"s":[209.6,201.9,0],"to":[0,0,0],"ti":[-8.458,24.508,0]},{"t":120,"s":[249.85,158.35,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":130,"s":[48,48,100]},{"t":140,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":141,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":138,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249.894,158.346,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":130,"s":[120,120,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":130,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".yellow400","cl":"yellow400","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0.092,-0.009,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[250,250,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":130,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":140,"s":[0]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":140,"op":305,"st":140,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"t":70,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0.78823530674,0.203921571374,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.644,201.896,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[90,90,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.158,0.158,0.158],"y":[0,0,0]},"t":70,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":140,"s":[100,100,100]},{"t":160,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.937254905701,0.764705896378,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"PersistentTaskbar_edu1","parent":13,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":113.5,"ix":3},"y":{"a":0,"k":16.5,"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":91,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":99,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":240,"s":[100]},{"t":245,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[348,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":111,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[348,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":3,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078431606,0.937254905701,0.764705896378,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[348,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.167,"y":0.167},"t":111,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[355.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[357,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[348,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":3,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[0,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[-7.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[-7.5,-1.45,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[-9,0,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[-9,0,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[0,0,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-95,-94,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[165,175]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,188]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,188]},{"t":260,"s":[190,188]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":0,"nm":"PersistentTaskbar_edu1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174.374,"ix":3},"y":{"a":0,"k":202,"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[{"tm":240,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_splitscreen_transient.json b/quickstep/res/raw/taskbar_edu_splitscreen_transient.json
index 786ae12..da0b6d7 100644
--- a/quickstep/res/raw/taskbar_edu_splitscreen_transient.json
+++ b/quickstep/res/raw/taskbar_edu_splitscreen_transient.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU1_Split","ddd":0,"assets":[{"id":"comp_0","nm":"TransientTaskbar_edu1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[227,33],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"gesture","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":140,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[185.75,174.4,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[209.3,191.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":70,"s":[209.3,191.5,0],"to":[0,0,0],"ti":[-8.458,24.508,0]},{"t":120,"s":[249.55,147.95,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":130,"s":[48,48,100]},{"t":140,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":141,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":138,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249.52,147.95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":130,"s":[120,120,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":130,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".yellow400","cl":"yellow400","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.063,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[208.333,208.333,100]},{"t":70,"s":[250,250,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":70,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":130,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"t":70,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":69,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":140,"s":[0]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":140,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":140,"op":301,"st":140,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.996,0.937,0.765,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996,0.937,0.765,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"TransientTaskbar 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":91,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":99,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":240,"s":[100]},{"t":245,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[339,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[339,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.996,0.937,0.765,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996,0.937,0.765,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[339,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[339,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[9,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[5,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[5,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[0,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[0,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[9,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":89,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":247,"s":[100]},{"t":250,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[192,123,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[192,123],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":360,"st":0,"ct":1,"bm":0}],"markers":[{"tm":240,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU1_Split","ddd":0,"assets":[{"id":"comp_0","nm":"TransientTaskbar_edu1","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"universale grey divider","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"universal grey action","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[227,33],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"gesture","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":140,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[185.75,174.4,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[209.3,191.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":70,"s":[209.3,191.5,0],"to":[0,0,0],"ti":[-8.458,24.508,0]},{"t":120,"s":[249.55,147.95,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":130,"s":[48,48,100]},{"t":140,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":141,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":130,"s":[100]},{"t":138,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[249.52,147.95,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.5],"y":[0,0,0]},"t":130,"s":[120,120,100]},{"t":140,"s":[100,100,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":130,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".yellow400","cl":"yellow400","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.063,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[208.333,208.333,100]},{"t":70,"s":[250,250,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":70,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":130,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":70,"op":130,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[100,100,100]},{"t":70,"s":[120,120,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":69,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":70,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.2],"y":[0]},"t":140,"s":[0]},{"t":160,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":140,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":140,"op":301,"st":140,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[209.27,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":60,"s":[90,90,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.158,0.158,0.158],"y":[0,0,0]},"t":70,"s":[100,100,100]},{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":140,"s":[100,100,100]},{"t":160,"s":[90,90,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.996,0.937,0.765,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996,0.937,0.765,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"TransientTaskbar 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,191.5,0],"ix":2,"l":2},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".yellow100","cl":"yellow100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":91,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":99,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":240,"s":[100]},{"t":245,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[339,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[339,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.996,0.937,0.765,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.996,0.937,0.765,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[339,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[343,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[348,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[339,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":91,"s":[9,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":111,"s":[5,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":140,"s":[5,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":0},"o":{"x":0.2,"y":0.2},"t":160,"s":[0,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0,"y":1},"o":{"x":0.2,"y":0},"t":240,"s":[0,109.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":260,"s":[9,109.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-86,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":91,"s":[190,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":111,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":140,"s":[158,195]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":160,"s":[172,219]},{"i":{"x":[0,0],"y":[1,1]},"o":{"x":[0.2,0.2],"y":[0,0]},"t":240,"s":[172,219]},{"t":260,"s":[190,219]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":89,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":92,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":247,"s":[100]},{"t":250,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[192,123,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[192,123],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[{"tm":240,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_stashing.json b/quickstep/res/raw/taskbar_edu_stashing.json
index 529a011..0dd997c 100644
--- a/quickstep/res/raw/taskbar_edu_stashing.json
+++ b/quickstep/res/raw/taskbar_edu_stashing.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU0_Unstash","ddd":0,"assets":[{"id":"comp_0","nm":"TransientTaskbar_edu0","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[148.77,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".grey300","cl":"grey300","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"k":[{"s":[0.855,0.863,0.878,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.855,0.863,0.878,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[227,33],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"swipe up","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"t":90,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[150.45,189.9,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[174,207,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":60,"s":[174,207,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[174,168.45,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":80,"s":[48,48,100]},{"t":90,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":91,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"TransientTaskbar","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"t":60,"s":[0],"h":1},{"t":72,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":65,"s":[207.918]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.33],"y":[0]},"t":90,"s":[186.5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":107,"s":[191.5]},{"i":{"x":[0.283],"y":[0.761]},"o":{"x":[0.2],"y":[0]},"t":210,"s":[191.5]},{"t":225,"s":[210.843]}],"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":72,"s":[43,43,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.999,0.999,0.999],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":210,"s":[100,100,100]},{"t":222,"s":[40,40,100]}],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":60,"op":222,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[100],"h":1},{"t":72,"s":[0],"h":1},{"t":222,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.5],"y":[0]},"t":60,"s":[208]},{"t":90,"s":[181],"h":1},{"i":{"x":[0.283],"y":[0.801]},"o":{"x":[0.314],"y":[0]},"t":210,"s":[191]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.7]},"t":222,"s":[211.989]},{"t":261,"s":[208]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[98,5.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":33,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 16568","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0}],"markers":[{"tm":210,"cm":"","dr":0},{"tm":218,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU0_Unstash","ddd":0,"assets":[{"id":"comp_0","nm":"TransientTaskbar_edu0","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[210.353,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.395,16.316,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[14.2,14.199],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue suggested","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[179.396,16.318,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"outer suggested blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[148.77,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"yellow","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[117.979,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"green","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[87.187,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.933,0.404,0.361,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.933,0.404,0.361,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"red","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".blue400","cl":"blue400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.396,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20.791,20.791],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"blue","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"universal grey divder","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[36,16.396,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-5,0],[5,0]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":90,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Divider","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"universal grey action","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.999],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":155,"s":[100]},{"t":162,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[21.033,17.175,0],"ix":2,"l":2},"a":{"a":0,"k":[7.033,6.779,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 12","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,9.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 11","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[2.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 1","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.381,0],[0,1.381],[1.381,0],[0,-1.381]],"o":[[1.381,0],[0,-1.381],[-1.381,0],[0,1.381]],"v":[[0,2.5],[2.5,0],[0,-2.5],[-2.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 5","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[9.613,2.414],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"circle 2","np":1,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.185,0.148],[0,0],[0,0],[0,0],[-0.086,0.24],[0,0.271],[0.468,0.462],[0.671,0],[0.468,-0.468],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.24,0.086]],"o":[[0,0],[0,0],[0,0],[0.148,-0.185],[0.086,-0.24],[0,-0.671],[-0.462,-0.468],[-0.671,0],[-0.462,0.462],[0,0.671],[0.468,0.462],[0.271,0],[0.24,-0.086]],"v":[[0.48,0.998],[2.809,3.326],[3.326,2.809],[0.998,0.48],[1.349,-0.157],[1.478,-0.924],[0.776,-2.624],[-0.924,-3.326],[-2.633,-2.624],[-3.326,-0.924],[-2.633,0.785],[-0.924,1.478],[-0.157,1.349]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462],[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462]],"o":[[-0.32,0.32],[-0.462,0],[-0.32,-0.326],[0,-0.462],[0.326,-0.326],[0.462,0],[0.326,0.32],[0,0.462]],"v":[[0.249,0.259],[-0.924,0.739],[-2.106,0.259],[-2.587,-0.924],[-2.106,-2.097],[-0.924,-2.587],[0.249,-2.097],[0.739,-0.924]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"st","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0.4,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.603921592236,0.627451002598,0.65098041296,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[10.627,10.318],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"icon","np":1,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[113.5,16.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[227,33],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":174,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":161,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Taskbar","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"swipe up","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":80,"s":[100]},{"t":90,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[150.45,189.9,0],"to":[3.425,5.892,0],"ti":[-15.2,-2.85,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[174,207,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.5,"y":0},"t":60,"s":[174,207,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[174,168.45,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":50,"s":[60,60,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":60,"s":[48,48,100]},{"i":{"x":[0.5,0.5,0.667],"y":[1,1,1]},"o":{"x":[0.5,0.5,0.333],"y":[0,0,0]},"t":80,"s":[48,48,100]},{"t":90,"s":[60,60,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"rc","d":1,"s":{"a":0,"k":[56,56],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":67,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":50,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":91,"st":5,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"TransientTaskbar","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"t":60,"s":[0],"h":1},{"t":72,"s":[100],"h":1},{"t":210,"s":[100],"h":1},{"t":221,"s":[0],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.5],"y":[0]},"t":65,"s":[207.918]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.33],"y":[0]},"t":90,"s":[186.5]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":107,"s":[191.5]},{"i":{"x":[0.283],"y":[0.809]},"o":{"x":[0.2],"y":[0]},"t":210,"s":[191.5]},{"t":222,"s":[210.843]}],"ix":4}},"a":{"a":0,"k":[113.5,16.5,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0,0,0],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":72,"s":[43,43,100]},{"i":{"x":[0.833,0.833,0.833],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":90,"s":[100,100,100]},{"i":{"x":[0.999,0.999,0.999],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":210,"s":[100,100,100]},{"t":222,"s":[40,40,100]}],"ix":6,"l":2}},"ao":0,"w":227,"h":33,"ip":60,"op":222,"st":60,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":1,"k":[{"t":0,"s":[100],"h":1},{"t":72,"s":[0],"h":1},{"t":221,"s":[100],"h":1}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":174,"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.5],"y":[0]},"t":60,"s":[208]},{"t":90,"s":[181],"h":1},{"i":{"x":[0.283],"y":[0.817]},"o":{"x":[0.314],"y":[0]},"t":210,"s":[191]},{"i":{"x":[0.1],"y":[1]},"o":{"x":[0.05],"y":[0.718]},"t":221,"s":[211.989]},{"t":261,"s":[208]}],"ix":4}},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"t":90,"s":[98,5.5],"h":1},{"i":{"x":[0.1,0.1],"y":[1,1]},"o":{"x":[0.05,0.05],"y":[0.718,0.718]},"t":221,"s":[106,11.5]},{"t":261,"s":[98,5.5]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":33,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 16568","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":366,"st":0,"ct":1,"bm":0}],"markers":[{"tm":210,"cm":"","dr":0},{"tm":218,"cm":"","dr":0}],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_suggestions_persistent.json b/quickstep/res/raw/taskbar_edu_suggestions_persistent.json
index d335fe1..4f1231d 100644
--- a/quickstep/res/raw/taskbar_edu_suggestions_persistent.json
+++ b/quickstep/res/raw/taskbar_edu_suggestions_persistent.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Persistent_EDU3","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_edu3_CU","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"greenMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":69,"s":[230,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":99,"s":[230,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":114,"s":[230,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"greenMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":66,"s":[230,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":96,"s":[230,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"blueMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":63,"s":[115,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":93,"s":[115,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":108,"s":[115,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"blueMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":60,"s":[115,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[115,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289,59,0],"ix":2,"l":2},"a":{"a":0,"k":[180,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[360,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":436,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320683","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_edu3_CU","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,219,0],"ix":2,"l":2},"a":{"a":0,"k":[144.5,118,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":289,"h":118,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,160,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320684","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Persistent_EDU3_Suggested","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_edu3_CU","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"greenMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":69,"s":[230,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":99,"s":[230,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":114,"s":[230,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"greenMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":66,"s":[230,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":96,"s":[230,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"blueMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":63,"s":[115,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":93,"s":[115,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":108,"s":[115,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"blueMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":60,"s":[115,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[115,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289,59,0],"ix":2,"l":2},"a":{"a":0,"k":[180,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[360,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":436,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320683","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_edu3_CU","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,219,0],"ix":2,"l":2},"a":{"a":0,"k":[144.5,118,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":289,"h":118,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,160,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.235,0.251,0.263,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.235,0.251,0.263,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320684","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/raw/taskbar_edu_suggestions_transient.json b/quickstep/res/raw/taskbar_edu_suggestions_transient.json
index 48d4d0a..1c0c36c 100644
--- a/quickstep/res/raw/taskbar_edu_suggestions_transient.json
+++ b/quickstep/res/raw/taskbar_edu_suggestions_transient.json
@@ -1 +1 @@
-{"v":"5.12.0","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU3","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_edu3_CU","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"greenMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":69,"s":[230,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":99,"s":[230,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":114,"s":[230,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"greenMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":66,"s":[230,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":96,"s":[230,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"blueMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":63,"s":[115,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":93,"s":[115,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":108,"s":[115,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"blueMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":60,"s":[115,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[115,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289,59,0],"ix":2,"l":2},"a":{"a":0,"k":[180,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[360,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":436,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320683","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_edu3_CU","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,109,0],"ix":2,"l":2},"a":{"a":0,"k":[144.5,59,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":289,"h":118,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
+{"v":"5.12.1","fr":60,"ip":0,"op":301,"w":348,"h":219,"nm":"Taskbar_Transient_EDU3_Suggested","ddd":0,"assets":[{"id":"comp_0","nm":"Taskbar_edu3_CU","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"greenMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":69,"s":[230,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":99,"s":[230,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":114,"s":[230,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"greenMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":".green400","cl":"green400","tt":1,"tp":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":66,"s":[230,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":96,"s":[230,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.357,0.725,0.455,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.357,0.725,0.455,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".green100","cl":"green100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[230,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.808,0.918,0.839,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.808,0.918,0.839,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320669","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"blueMatteTwo","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":63,"s":[115,149,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.5,"y":1},"o":{"x":0.3,"y":0},"t":93,"s":[115,57,0],"to":[0,0,0],"ti":[0,0,0]},{"t":108,"s":[115,59,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"blueMatteOne","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.988235294819,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".blue400","cl":"blue400","tt":1,"tp":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.3,"y":1},"o":{"x":0.8,"y":0},"t":60,"s":[115,59,0],"to":[0,0,0],"ti":[0,0,0]},{"t":90,"s":[115,-31,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"k":[{"s":[0.4,0.616,0.965,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.4,0.616,0.965,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 7508","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.824,0.89,0.988,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.824,0.89,0.988,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".yellow400","cl":"yellow400","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,59,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[78,78],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":100,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"k":[{"s":[0.988,0.788,0.204,1],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[0.988,0.788,0.204,1],"t":300,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320670","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey800","cl":"grey800","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[289,59,0],"ix":2,"l":2},"a":{"a":0,"k":[180,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[360,118],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":436,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Frame 1321320683","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":1250,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Taskbar_edu3_CU","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.5,109,0],"ix":2,"l":2},"a":{"a":0,"k":[144.5,59,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":289,"h":118,"ip":0,"op":301,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".blue100","cl":"blue100","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174,109.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[348,219],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":16,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.823529422283,0.890196084976,0.988235294819,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":301,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index a6da872..6a749d1 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Maak seker dat jy van die rand heel regs of heel links af swiep"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Maak seker dat jy van die regter- of linkerrand af na die middel van die skerm toe swiep en laat los"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Jy het geleer hoe om van regs af te swiep om terug te gaan. Nou kan jy leer hoe om tussen apps te wissel."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Jy het die \"gaan terug\"-gebaar voltooi. Nou kan jy leer hoe om tussen programme te wissel."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Jy het die Gaan Terug-gebaar voltooi"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Maak seker dat jy nie te naby aan die onderkant van die skerm swiep nie"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Gaan na Instellings om sensitiwiteit van teruggebaar te verander"</string>
@@ -92,9 +94,11 @@
     <string name="default_device_name" msgid="6660656727127422487">"toestel"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Stelselnavigasie-instellings"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Deel"</string>
-    <string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
+    <string name="action_screenshot" msgid="8171125848358142917">"Skermskoot"</string>
     <string name="action_split" msgid="2098009717623550676">"Verdeel"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Stoor app-paar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies ’n ander app as jy verdeelde skerm wil gebruik"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselleer"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Verlaat verdeeldeskermkeuse"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies nog ’n app as jy verdeelde skerm wil gebruik"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Kry appvoorstelle op grond van jou roetine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Langdruk op die verdeler om die Taakbalk vas te speld"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Doen meer met die Taakbalk"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Wys altyd die Taakbalk"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Raak en hou die verdeler in om altyd die Taakbalk onderaan jou skerm te wys"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Raak en hou die aksiesleutel om te soek wat op jou skerm is"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Hierdie produk gebruik die deel van jou skerm wat gekies is om te soek. Google se <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privaatheidsbeleid<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> en <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>diensbepalings<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> geld."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Maak toe"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Tuis"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taakbalk word gewys"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taakbalk is versteek"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigasiebalk"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Wys Taakbalk altyd"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Wys altyd Taakbalk"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Verander navigasiemodus"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taakbalkverdeler"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index a825e3e..500cc3d 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ከቀኝ ጥግ ወይም ከግራ ጥግ ጠርዝ ጀምሮ ማንሸራተትዎን ያረጋግጡ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ከቀኝ ወይም ከግራ ጠርዝ ወደ ማያ ገጹ መሃል ማንሸራተትዎን እና መልቀቅዎን ያረጋግጡ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ወደ ኋላ ለመመለስ ከቀኝ ጀምሮ እንዴት ማንሸራተት እንደሚችሉ አውቀዋል። ቀጥለው መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ወደኋላ የመመለስ ምልክትን አጠናቀዋል። ቀጥሎም መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ወደኋላ የመመለስ ምልክትን አጠናቅቀዋል"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ከማያ ገጹ ታችኛው ክፍል ጋር በጣም ጠጋ ብለው አለማንሸራተትዎን ያረጋግጡ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ከኋላ ስሜት ሰጭነት ደረጃ ለመለወጥ ወደ ቅንብሮች ይመለሱ"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገፅ ዕይታ"</string>
     <string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"የመተግበሪያ ጥምረትን አስቀምጥ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ ይምረጡ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ይቅር"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ከተከፈለ ማያ ገፅ ምርጫ ይውጡ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"የተከፈለ ማያ ገጽን ለመቀበል ሌላ መተግበሪያ ይምረጡ"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"በዕለት ተዕለት ተግባርዎ መሠረት የመተግበሪያ አስተያየቶችን ያግኙ"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"የተግባር አሞሌውን ፒን ለማድረግ በአከፋፋዩ ላይ በረጅሙ ይጫኑ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"በተግባር አሞሌው ተጨማሪ ነገር ያድርጉ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"የተግባር አሞሌውን ሁልጊዜ አሳይ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"በማያ ገጽዎ ግርጌ ላይ ያለውን የተግባር አሞሌ ሁልጊዜ ለማሳየት፣ መክፈያን ይንኩ እና ይያዙ"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"በማያ ገጽዎ ላይ ያለውን ነገር ለመፈለግ የተግባር ቁልፉን ነክተው ይያዙ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ይህ ምርት የተመረጠውን የማያ ገጽዎን ክፍል ለመፈለግ ይጠቀማል። የGoogle <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>የግላዊነት መመሪያ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> እና <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>የአገልግሎት ውል<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ተፈጻሚ ናቸው።"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ተጠናቅቋል"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"መነሻ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 09f146c..de2c8b1 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -21,7 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ما مِن عناصر تم استخدامها مؤخرًا"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"التطبيقات المستخدمة مؤخرًا"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"تأكَّد من التمرير سريعًا من أقصى الحافة اليسرى أو اليمنى."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"تأكَّد من التمرير سريعًا من الحافة اليسرى أو اليمنى إلى وسط الشاشة ثم ارفع إصبعك."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"لقد تعلمت كيفية التمرير سريعًا من اليسار للرجوع. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"لقد أكملت التدريب على إيماءة الرجوع. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"لقد أكملت التدريب على إيماءة الرجوع."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"تأكَّد من عدم التمرير سريعًا بالقرب من أسفل الشاشة."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"لتغيير مستوى حساسية إيماءة الرجوع، انتقِل إلى \"الإعدادات\""</string>
@@ -94,10 +96,12 @@
     <string name="action_share" msgid="2648470652637092375">"مشاركة"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
     <string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"حفظ استخدام التطبيقين معًا"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\""</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"إلغاء"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"الخروج من وضع تقسيم الشاشة"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\""</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"التطبيقات المصغّرة غير متوفّرة حاليًا، يرجى اختيار تطبيق آخر."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي للتنقّل؟"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"التخطي"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"تدوير الشاشة"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"التعريف بشريط التطبيقات"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"اسحب تطبيقًا إلى جانب الشاشة لاستخدام تطبيقََين في آنٍ واحد."</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"اسحب تطبيقًا إلى جانب الشاشة لاستخدام تطبيقََين في آنٍ واحد"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"مرِّر ببطء للأعلى لإظهار شريط التطبيقات"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"احصل على اقتراحات التطبيقات بناءً على سلسلة إجراءاتك."</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"احصل على اقتراحات التطبيقات بناءً على سلسلة إجراءاتك"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"اضغط مع الاستمرار على المقسِّم لتثبيت \"شريط التطبيقات\""</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"إنجاز المزيد باستخدام شريط التطبيقات"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"عرض \"شريط التطبيقات\" دائمًا"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"انقر مع الاستمرار على أداة تقسيم الشاشة لعرض \"شريط التطبيقات\" دائمًا في أسفل الشاشة."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"انقر مع الاستمرار على مفتاح الإجراء للبحث عن المحتوى الذي يظهر على شاشتك"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏يستخدم هذا المنتج الجزء المحدّد من الشاشة للبحث. تسري <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>سياسة خصوصية<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> Google و<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>بنود خدمتها<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تم"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"الرئيسية"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index ea95d2c..c483fb1 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"আটাইবোৰ মচক"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"আপুনি সোঁ অথবা বাওঁ কাষৰ একেবাৰে সীমাৰ পৰা ছোৱাইপ কৰাটো নিশ্চিত কৰক"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"আপুনি স্ক্ৰীনৰ সোঁ অথবা বাওঁ কাষৰ পৰা মধ্যভাগলৈকে ছোৱাইপ কৰি এৰি দিয়াটো নিশ্চিত কৰক"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"সোঁফালৰ পৰা ছোৱাইপ কৰি কেনেকৈ উভতি যাব লাগে, সেইটো আপুনি জানিলে। ইয়াৰ পাছত, এপ্‌ কেনেকৈ সলনি কৰিব সেয়া জানক।"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। ইয়াৰ পাছত, এপ্‌ কেনেকৈ সলনি কৰিব সেয়া জানক।"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"আপুনি স্ক্ৰীনৰ তলৰ অংশৰ বেছি ওচৰলৈ ছোৱাইপ নকৰাটো নিশ্চিত কৰক"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"উভতি যোৱাৰ নির্দেশটোৰ সংবেদনশীলতা সলনি কৰিবলৈ ছেটিঙলৈ যাওক"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
     <string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"এপৰ পেয়াৰ ছেভ কৰক"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছনি কৰক"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল কৰক"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"বিভাজিত স্ক্ৰীনৰ বাছনিৰ পৰা বাহিৰ হওক"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছক"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"আপোনাৰ ৰুটিনৰ ওপৰত আধাৰিত এপৰ পৰামৰ্শ পাওক"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"টাস্কবাৰ পিন কৰিবলৈ বিভাজকত দীঘলীয়া সময় টিপি থাকক"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"টাস্কবাৰৰ জৰিয়তে অধিক কাৰ্য সম্পাদন কৰক"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবাৰডাল সদায় দেখুৱাওক"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"আপোনাৰ স্ক্ৰীনৰ তলত সদায় টাস্কবাৰডাল দেখুৱাবলৈ বিভাজকডাল স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"আপোনাৰ স্ক্ৰীনখনত থকা সমল সন্ধান কৰিবলৈ কাৰ্য কীটো স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"এই প্ৰ’ডাক্টটোৱে সন্ধান কৰিবলৈ আপোনাৰ স্ক্ৰীনখনৰ বাছনি কৰা অংশ ব্যৱহাৰ কৰে। Googleৰ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>গোপনীয়তাৰ নীতি<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> আৰু <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>সেৱাৰ চৰ্তাৱলী<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> প্ৰযোজ্য।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হ’ল"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"গৃহপৃষ্ঠা"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 510749c..1500e82 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ən sağ və ya sol kənardan sürüşdürün"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sağ və ya sol kənardan ekranın ortasına sürüşdürüb, buraxın"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Geri qayıtmaq üçün sağdan sürüşdürmək qaydasını öyrəndiniz. Sonra tətbiqləri keçirməyi öyrənin."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Geri getmə jestini tamamladınız. Sonra tətbiqləri keçirməyi öyrənin."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Geri qayıtma jestini tamamladınız"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Barmağınızı ekranın aşağı kənarına çox yaxınlaşdırmayın"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Geri qayıtma jestinin həssaslığını dəyişmək üçün Ayarlara keçin"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Paylaşın"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string>
     <string name="action_split" msgid="2098009717623550676">"Ayırın"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Tətbiq cütünü saxla"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ləğv edin"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçimindən çıxın"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Rejiminizə əsasən tətbiq təklifləri alın"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Ayırıcı üzərinə basıb saxlayaraq İşləmə panelini bərkidin"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tapşırıq paneli ilə daha çox şey edin"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"İşləmə panelini həmişə göstərin"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"İşləmə panelini həmişə ekranın aşağısında göstərmək üçün ayırıcı üzərinə toxunun və saxlayın"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekranda axtarış etmək üçün fəaliyyət açarına toxunub saxlayın"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu məhsul axtarış üçün ekranın seçilmiş hissəsindən istifadə edir. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Məxfilik Siyasəti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> və <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Xidmət Şərtləri<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> tətbiq edilir."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Bağlayın"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hazırdır"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ev"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 79e3616..9529776 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Obavezno prevucite od same desne ili leve ivice"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dovršili ste pokret za povratak. Sada saznajte kako da promenite aplikacije."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dovršili ste pokret za povratak"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nikako ne prevlačite previše blizu dna ekrana"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osetljivost pok. za nazad možete da promenite u Podešavanjima"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Deli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podeli"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da biste koristili podeljeni ekran"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlazak iz biranja podeljenog ekrana"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Uputstva na traci zadataka"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Prevucite na stranu da biste koristili 2 aplikacije odjednom"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Sporo prevucite nagore da biste prikazali traku zadataka"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Sporo prevucite nagore da biste videli traku zadataka"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dobijajte predloge aplikacija na osnovu rutine"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dugo pritiskajte razdelnik da biste zakačili traku zadataka"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dugo pritisnite razdelnik da biste zakačili traku zadataka"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvek prikazuj traku zadataka"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi traka zadataka uvek bila prikazana u dnu ekrana, dodirnite i zadržite razdelnik"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite taster radnji da biste pretražili ono što je na ekranu"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod koristi izabrani deo ekrana za pretragu. Primenjuju se Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>politika privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uslovi korišćenja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index c164f95..6b20866 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ачысціць усё"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Правядзіце пальцам справа налева ці злева направа ад самага краю экрана"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Правядзіце пальцам ад правага або левага краю экрана ў цэнтр і адпусціце палец"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Вы даведаліся, як гартаць справа для вяртання. Цяпер даведайцеся, як пераключацца паміж праграмамі."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Вы навучыліся рабіць жэст вяртання. А зараз даведайцеся, як пераключацца паміж праграмамі."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Вы навучыліся рабіць жэст для пераходу назад"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не праводзьце пальцам занадта блізка да ніжняга краю экрана"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Каб змяніць адчувальнасць жэста вяртання, адкрыйце налады"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Абагуліць"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Захаваць спалучэнне"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Каб карыстацца рэжымам падзеленага экрана, выберыце другую праграму"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасаваць"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйсці з рэжыму падзеленага экрана"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Каб падзяліць экран, выберыце іншую праграму"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Атрымлівайце прапановы праграм з улікам вашых дзеянняў"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Замацуйце панэль задач доўгім націсканнем на раздзяляльнік"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Выкарыстоўвайце магчымасці панэлі задач"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Замацуйце панэль задач унізе экрана"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для гэтага націсніце на раздзяляльнік і ўтрымлівайце яго"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Каб выканаць пошук па тым, што адлюстравана на экране, націсніце і ўтрымлівайце клавішу дзеяння"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Гэты прадукт выконвае пошук па змесціве выбранай часткі экрана. Дзейнічаюць <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Умовы выкарыстання<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> і <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Палітыка прыватнасці<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Гатова"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Галоўны экран"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 9239089..8631d8b 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Изчистване на всички"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Трябва да плъзнете пръст от най-дясната или най-лявата част на екрана"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Трябва да плъзнете пръст от десния или левия край до средата на екрана, след което да го отпуснете"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научихте жеста за връщане с плъзгане от дясно. Сега научете как се превключва между приложения."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Изпълнихте жеста за връщане назад. В следващия урок ще научите как се превключва между приложения."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Изпълнихте жеста за връщане назад"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не плъзвайте пръста си твърде близо до долната част на екрана"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Променете чувств. на жеста за връщане назад от настройките"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Споделяне"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
     <string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Запис на двойка приложения"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Докоснете друго прил., за да ползвате разд. екран"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"За разделен екран изберете още едно приложение"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отказ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Изход от избора на разделен екран"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"За разделен екран изберете още едно приложение"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Получавайте предложения за приложения според навиците си"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Натиснете продължително разделителя, за да фиксирате лентата на задачите"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повече неща с лентата на задачите"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Лентата на задачите да се показва винаги"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"За да фиксирате лентата на задачите най-долу на екрана, докоснете и задръжте разделителя"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Докоснете и задръжте клавиша за действия, за да извършите търсене със съдържанието на екрана"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Този продукт използва избраната част на екрана ви, за да търси. Прилагат се <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Декларацията за поверителност<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Общите условия<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> на Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Начало"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 80d0275..948d07d 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -21,7 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"কোনো সাম্প্রতিক আইটেম নেই"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
+    <string name="recents_empty_message" msgid="7040467240571714191">"কোনও সাম্প্রতিক আইটেম নেই"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"সবকিছু খালি করুন"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"সম্প্রতি ব্যবহৃত অ্যাপ"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"স্ক্রিনের একেবারে ডান বা বাঁদিকের প্রান্ত থেকে সোয়াইপ করেছেন কিনা তা দেখে নিন"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"স্ক্রিনের ডান বা বাঁদিকের প্রান্ত থেকে মাঝখান পর্যন্ত সোয়াইপ করেছেন কিনা দেখে নিয়ে আঙুল তুলে নিন"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ফিরে যেতে, কীভাবে ডানদিক থেকে সোয়াইপ করতে হয় তা আপনি শিখেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"আপনি ফিরে যাওয়ার জেসচার সম্পর্কে জেনেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"আপনি জেনেছেন হাতের জেসচার ব্যবহার করে আগের স্ক্রিনে কীভাবে ফিরে যাওয়া যায়"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"স্ক্রিনের নিচের প্রান্তের খুব কাছে পর্যন্ত যাতে সোয়াইপ না করেন সেটি ভাল করে দেখে নিন"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ফিরে যাওয়ার জেসচারের সেন্সিটিভিটি পরিবর্তন করতে, সেটিংসে যান"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
     <string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"অ্যাপ পেয়ার সেভ করুন"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল করুন"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"স্প্লিট স্ক্রিন বেছে নেওয়ার বিকল্প থেকে বেরিয়ে আসুন"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
@@ -107,10 +112,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্রিন ঘোরান"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"টাস্কবার এডুকেশন"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"একসাথে ২টি অ্যাপ ব্যবহার করতে একটি অ্যাপ পাশে টেনে আনুন"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"\'টাস্কবার\' দেখানোর জন্য উপরের দিকে আস্তে সোয়াইপ করুন"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"\'টাস্কবার\' দেখার জন্য উপরের দিকে ধীরে সোয়াইপ করুন"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"আপনার রুটিন অনুযায়ী অ্যাপ থেকে সাজেশন পান"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"টাস্কবার পিন করতে, ড্রাইভার বেশ কিছুক্ষণ প্রেস করে রাখুন"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"\'টাস্কবার\' পিন করতে, ডিভাইডার বেশ কিছুক্ষণ প্রেস করে রাখুন"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"\'টাস্কবার\' ফিচারের সাহায্যে আরও অনেক কিছু করুন"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"টাস্কবার সবসময় দেখানো"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"স্ক্রিনের নিচে টাস্কবার সবসময় দেখাতে ডিভাইডার টাচ করে ধরে থাকুন"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"আপনার স্ক্রিনে দেখতে পাওয়া কন্টেন্ট সার্চ করতে অ্যাকশন কী স্পর্শ করে ধরে রাখুন"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"সার্চ করার জন্য এই প্রোডাক্ট স্ক্রিনের বেছে নেওয়া অংশটুকু ব্যবহার করে। Google-এর <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>গোপনীয়তা নীতি<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> এবং <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>পরিষেবার শর্তাবলী<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> প্রযোজ্য।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ করুন"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হয়ে গেছে"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"হোম"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index e22e856..15da445 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili krajnjeg lijevog ruba"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Prevucite s desnog ili lijevog ruba prema sredini ekrana i pustite"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prevući zdesna da se vratite. Sljedeće naučite kako prebacivati između aplikacija."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Savladali ste pokret za vraćanje. Sljedeće naučite kako prebacivati između aplikacija."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Savladali ste pokret za vraćanje"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite da ne prevučete preblizu donjem dijelu ekrana"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Promijenite osjetljivost pokreta za povratak u Postavkama"</string>
@@ -76,7 +79,7 @@
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da prebacujete između aplikacija"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Da se prebacujete između aplikacija, prevucite s dna ekrana nagore, zadržite, a zatim pustite."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Da se prebacujete između aplikacija, prevucite s 2 prsta od dna ekrana, zadržite, a zatim pustite."</string>
-    <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Prebacujte se između aplikacija"</string>
+    <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Prebacujte između aplikacija"</string>
     <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Prevucite s dna ekrana prema gore, zadržite, a zatim pustite"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Odlično!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Sve je spremno"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da koristite podijeljeni ekran"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izlaz iz odabira podijeljenog ekrana"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu apl. da koristite podijeljeni ekran"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dobijajte prijedloge aplikacija zasnovane na vašoj rutini"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Pritisnite i zadržite razdjelnik da zakačite traku zadataka"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Uradite više pomoću trake zadataka"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz trake zadataka"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da se traka zadataka uvijek prikazuje na dnu ekrana, dodirnite i zadržite razdjelnik"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku radnji da pretražite sadržaj na ekranu"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod koristi odabrani dio ekrana za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Pravila privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Uslovi korištenja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Dom"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index df8cb36..62ae01b 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assegura\'t de lliscar des de l\'extrem dret o esquerre de la pantalla."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assegura\'t de lliscar des de la vora dreta o esquerra cap al centre de la pantalla i deixar anar"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Has après a lliscar des de la dreta per tornar enrere. Ara, descobreix com pots canviar d\'aplicació."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Has completat el gest per tornar enrere. Ara, descobreix com pots canviar d\'aplicació."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Has completat el gest per tornar enrere"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assegura\'t de no lliscar massa a prop de la part inferior de la pantalla."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Per canviar la sensibilitat del gest, ves a Configuració"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Comparteix"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Divideix"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Desa la parella d\'apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Tria una altra aplicació per utilitzar la pantalla dividida"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel·la"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Surt de la selecció de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Tria una altra app per utilitzar pantalla dividida"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén suggeriments d\'aplicacions basats en la teva rutina"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén premut el separador per fixar la Barra de tasques"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Treu més partit de la Barra de tasques"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la Barra de tasques"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Perquè es mostri sempre la Barra de tasques a la part inferior de la pantalla, mantén premut el separador"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén premuda la tecla d\'acció per cercar què es mostra a la pantalla"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>condicions del servei<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inici"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Es mostra la Barra de tasques"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"S\'ha amagat la Barra de tasques"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegació"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Mostra sempre Barra de tasques"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tasques sempre visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Canvia el mode de navegació"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador de la Barra de tasques"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 1cd2ed9..a07ffc5 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -21,7 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"Žádné nedávné položky"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"Poslední aplikace"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Přejeďte prstem z úplného pravého nebo levého okraje obrazovky"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Přejeďte prstem z pravého nebo levého okraje doprostřed obrazovky a zdvihněte prst"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili jste se, jak se vrátit zpět přejetím prstem zprava. Teď se naučíte přepínat mezi aplikacemi."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili jste gesto pro přechod zpět. Teď se naučíte přepínat aplikace."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dokončili jste gesto pro přechod zpět"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Dejte pozor, abyste prstem nepřejížděli moc blízko ke spodnímu okraji obrazovky"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Citlivost gesta pro přechod zpět můžete změnit v Nastavení"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
     <string name="action_split" msgid="2098009717623550676">"Rozdělit"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Uložit dvojici aplikací"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdělíte klepnutím na jinou aplikaci"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Výběrem další aplikace rozdělíte obrazovku"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušit"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Výběr opuštění rozdělené obrazovky"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vyberte podporovanou aplikaci"</string>
@@ -109,8 +113,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Přetáhněte aplikaci na stranu a používejte tak dvě najednou"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Panel aplikací zobrazíte pomalým přejetím prstem nahoru"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dostávejte návrhy aplikací podle toho, jaké používáte"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dlouhým stisknutím oddělovače připnete panel aplikací"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dlouhým stisknutím oddělovače panel aplikací připnete"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Více možností s panelem aplikací"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stálé zobrazení panelu aplikací"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pokud chcete, aby se panel aplikací vždy zobrazoval ve spodní části obrazovky, podržte oddělovač."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Podržením akční klávesy můžete vyhledat obsah na obrazovce"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Tato služba používá k vyhledávání vybranou část obrazovky. Platí <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>zásady ochrany soukromí<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> a <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>smluvní podmínky<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> společnosti Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Domů"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index d8f84dc..a1ca3c5 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ryd alt"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Stryg fra kanten yderst til højre eller venstre"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Stryg fra højre eller venstre kant mod midten af skærmen, og løft fingeren"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du har lært, hvordan du stryger fra højre for at gå tilbage. Nu skal du se, hvordan du skifter app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har fuldført bevægelsen for Gå tilbage. Som det næste kan du se, hvordan du skifter app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har fuldført bevægelsen for Gå tilbage"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Undgå at stryge for tæt på bunden af skærmen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Juster følsomheden for bevægelsen Gå tilbage i Indstillinger"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Del"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Opdel"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Gem appsammenknytning"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Vælg en anden app for at bruge opdelt skærm"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuller"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Luk valg af opdelt skærm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag baseret på din rutine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Fastgør proceslinjen med et langt tryk på skillelinjen"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Få mere fra hånden med proceslinjen"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis altid proceslinjen"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Hvis du vil have, at proceslinjen altid vises nederst på din skærm, skal du holde fingeren på skillelinjen"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Hold fingeren på handlingstasten for at søge efter det, der vises på din skærm"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dette produkt bruger den valgte del af din skærm til at søge. Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privatlivspolitik<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>servicevilkår<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> er gældende."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Luk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Luk"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 3d4ce43..73c3f04 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alle Apps schließen"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Wische vom äußersten rechten oder linken Displayrand"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Wische vom rechten oder linken Displayrand zur Displaymitte und lass los"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du hast jetzt gelernt, vom rechten Displayrand aus zu wischen, um zurückzugehen. Gleich erfährst du, wie man zwischen Apps wechselt."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du hast die „Zurück“-Touch-Geste abgeschlossen. Gleich lernst du, wie man zwischen Apps wechselt."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du hast den Schritt für die „Zurück“-Touch-Geste abgeschlossen"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Wische nicht zu nah an den unteren Displayrand"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Du kannst die Empfindlichkeit von „Zurück“ in den Einstellungen ändern"</string>
@@ -65,7 +68,7 @@
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Den Startbildschirm aufrufen"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Wische mit zwei Fingern vom unteren Displayrand nach oben. So gelangst du immer zum Startbildschirm."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum StartU+00AD­bildschirm"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum Start­bildschirm"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Wische vom unteren Displayrand nach oben"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Gut gemacht!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Wische vom unteren Displayrand nach oben"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Teilen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Abbrechen"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Splitscreen-Auswahl beenden"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für Splitscreen andere App auswählen"</string>
@@ -107,10 +112,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Bildschirm drehen"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informationen zur Taskleiste"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"App zur Seite ziehen, um zwei Apps gleichzeitig zu nutzen"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Langsam nach oben wischen, um die Taskleiste anzuzeigen"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Langsam nach oben wischen, um die Taskleiste zu sehen"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"App-Vorschläge auf Grundlage deiner Nutzung erhalten"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Bildschirmteiler lange drücken, um die Taskleiste anzupinnen"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Mehr Möglichkeiten mit der Taskleiste"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskleiste immer anzeigen"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Damit die Taskleiste immer unten angezeigt wird, halte den Teiler gedrückt"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Aktionstaste gedrückt halten, um auf dem Bildschirm zu suchen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dieses Produkt verwendet den ausgewählten Teil deines Bildschirms für die Suche. Es gelten die <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Datenschutzerklärung<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> und die <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Nutzungsbedingungen<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> von Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fertig"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Startbildschirm"</string>
@@ -129,7 +138,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen.}other{# weitere Apps anzeigen.}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Hinzufügen einer App zum Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Abbrechen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 335ebac..55e535b 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Υπολογιστής"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Φροντίστε να σύρετε από το άκρο της δεξιάς ή της αριστερής πλευράς."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Σύρετε από το δεξί ή το αριστερό άκρο προς το κέντρο της οθόνης και απομακρύνετε το δάχτυλό σας"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Μάθατε πώς να σύρετε από τα δεξιά για επιστροφή. Τώρα, μάθετε πώς να κάνετε εναλλαγή εφαρμογών."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ολοκληρώσατε την κίνηση επιστροφής. Στη συνέχεια, μάθετε πώς να κάνετε εναλλαγή εφαρμογών."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ολοκληρώσατε την κίνηση επιστροφής"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Φροντίστε να μην σύρετε υπερβολικά κοντά στο κάτω μέρος της οθόνης"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Μεταβείτε στις Ρυθμίσεις για αλλαγή ευαισθ. κίνησης επιστρ."</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
     <string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Αποθήκ. ζεύγ. εφαρμ."</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ακύρωση"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Έξοδος από την επιλογή διαχωρισμού οθόνης"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Λάβετε προτεινόμενες εφαρμογές με βάση τη ρουτίνα σας"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Παρατετ. πάτημα στο διαχωρ. για καρφ. της Γραμμής εργαλείων"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Κάντε περισσότερα με τη Γραμμή εργαλείων"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Να εμφανίζεται πάντα η Γραμμή εργαλείων"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Για να εμφανίζεται πάντα η Γραμμή εργαλείων στο κάτω μέρος της οθόνης, αγγίξτε παρατεταμένα το διαχωριστικό"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Αγγίξτε παρατεταμένα το πλήκτρο ενέργειας για να αναζητήσετε το περιεχόμενο της οθόνης"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Αυτό το προϊόν χρησιμοποιεί το επιλεγμένο τμήμα της οθόνης σας για αναζήτηση. Ισχύουν η <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Πολιτική απορρήτου<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> και οι <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Όροι Παροχής Υπηρεσιών<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> της Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Τέλος"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Αρχική σελίδα"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Η γραμμή εργαλείων εμφανίζεται"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Η γραμμή εργαλείων είναι κρυφή"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Γραμμή πλοήγησης"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Εμφ. πάντα σε Γραμμή εργαλείων"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Εμφάνιση Γραμμής εργαλείων"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Αλλαγή τρόπου πλοήγησης"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Διαχωριστικό Γραμμής εργαλείων"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 04ec03f..64c68e0 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Share"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Long press on the divider to pin the Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 5c8d0f2..4daaa90 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You learned how to swipe from the right to go back. Next up, learn how to switch apps."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next up, learn how to switch apps."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change the sensitivity of the back gesture, go to Settings"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Share"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Long press on the divider to pin the Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch &amp; hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 04ec03f..64c68e0 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Share"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Long press on the divider to pin the Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 04ec03f..64c68e0 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Share"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Save app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choose another app to use split screen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Exit split screen selection"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choose another app to use split screen"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Long press on the divider to pin the Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Do more with the Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Always show the Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"To always show the Taskbar on the bottom of your screen, touch and hold the divider"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Touch and hold the action key to search what\'s on your screen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"This product uses the selected part of your screen to search. Google\'s <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacy Policy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> and <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Terms of Service<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> apply."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 5d705ff..19e6aa0 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎Pin‎‏‎‎‏‎"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎Freeform‎‏‎‎‏‎"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎Desktop‎‏‎‎‏‎"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎No recent items‎‏‎‎‏‎"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎App usage settings‎‏‎‎‏‎"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‏‏‎Clear all‎‏‎‎‏‎"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‎‏‎Make sure you swipe from the far-right or far-left edge‎‏‎‎‏‎"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‎Make sure you swipe from the right or left edge to the middle of the screen and let go‎‏‎‎‏‎"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‏‏‎You learned how to swipe from the right to go back. Next up, learn how to switch apps.‎‏‎‎‏‎"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‎You completed the go back gesture. Next up, learn how to switch apps.‎‏‎‎‏‎"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‏‏‎‎You completed the go back gesture‎‏‎‎‏‎"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‎Make sure you don\'t swipe too close to the bottom of the screen‎‏‎‎‏‎"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎To change the sensitivity of the back gesture, go to Settings‎‏‎‎‏‎"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎Share‎‏‎‎‏‎"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎Screenshot‎‏‎‎‏‎"</string>
     <string name="action_split" msgid="2098009717623550676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎Split‎‏‎‎‏‎"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎Save app pair‎‏‎‎‏‎"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎Tap another app to use split screen‎‏‎‎‏‎"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‎‎Choose another app to use split screen‎‏‎‎‏‎"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‎"<b>"‎‏‎‎‏‏‏‎Cancel‎‏‎‎‏‏‎"</b>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎Exit split screen selection‎‏‎‎‏‎"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‏‎‎Choose another app to use split screen‎‏‎‎‏‎"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎Get app suggestions based on your routine‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‏‎‎Long press on the divider to pin the Taskbar‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎Do more with the Taskbar‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎Always show the Taskbar‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‎To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎Touch &amp; hold the action key to search what\'s on your screen‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‏‎‏‎‏‎This product uses the selected part of your screen to search. Google\'s ‎‏‎‎‏‏‎<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Privacy Policy‎‏‎‎‏‏‎<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‏‎<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>‎‏‎‎‏‏‏‎Terms of Service‎‏‎‎‏‏‎<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>‎‏‎‎‏‏‏‎ apply.‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎Close‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎Done‎‏‎‎‏‎"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎Home‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index a25bd7c..aa568f3 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cerrar todo"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de deslizar desde el extremo derecho o izquierdo"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Recuerda deslizar desde el borde izquierdo o derecho hacia el centro de la pantalla y, luego, soltar"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ya sabes deslizar el dedo desde la derecha para ir atrás. Ahora, descubre cómo cambiar de app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Completaste el gesto \"Atrás\". A continuación, obtén información para cambiar de app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Completaste el gesto para ir atrás"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Asegúrate de no deslizar muy cerca de la parte inferior de la pantalla"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Cambia sensibilidad de gesto \"Atrás\" en Configuración"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar vinculación"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar pantalla"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Información sobre la barra de tareas"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra una app a un lado para usar 2 apps a la vez"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Desliza despacio hacia arriba para ver la Barra de tareas"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Recibe sugerencias de aplicaciones basadas en tu rutina"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra una app hacia un lado para usar 2 apps a la vez"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Desliza lento hacia arriba para ver la Barra de tareas"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Recibe sugerencias de apps basadas en tu rutina"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén presionado el divisor para fijar la Barra de tareas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Aprovecha mejor la Barra de tareas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la Barra de tareas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Mantén presionado el divisor para mostrar siempre la Barra de tareas en la parte inferior de la pantalla"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén presionada la tecla de acción para buscar qué hay en la pantalla"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este producto usa la parte seleccionada de la pantalla para buscar. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> y las <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Condiciones del Servicio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Botón de inicio"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Ver siempre la Barra de tareas"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de la Barra de tareas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index bb2f533..27eceb8 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de deslizar desde el borde derecho o izquierdo de la pantalla"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Asegúrate de deslizar desde el borde derecho o izquierdo de la pantalla hasta el centro y soltar"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ya sabes deslizar el dedo desde la derecha para ir atrás. Descubre ahora cómo cambiar de aplicación."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Has completado el gesto para volver. Ahora, descubre cómo cambiar de aplicación."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Has completado el gesto para volver"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"No deslices demasiado cerca de la parte inferior de la pantalla"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Para cambiar la sensibilidad del gesto, ve a Ajustes"</string>
@@ -86,7 +89,7 @@
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"¡Muy bien!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"¡Ya está!"</string>
-    <string name="allset_hint" msgid="459504134589971527">"Desliza el dedo hacia arriba para ir a la pantalla de inicio"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Desliza hacia arriba para ir a la pantalla de inicio"</string>
     <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>
@@ -94,10 +97,12 @@
     <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>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar apps emparejadas"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra aplicación para usar la pantalla dividida"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"Actualmente no se admiten widgets; selecciona otra aplicación"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra una aplicación hacia un lado para usar 2 a la vez"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Desliza hacia arriba lentamente para ver la barra de tareas"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén sugerencias de aplicaciones basadas en tu rutina"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén pulsado el divisor para fijar Barra de tareas"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén pulsado el divisor para fijar la barra de tareas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Sácale más partido a la barra de tareas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la barra de tareas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar siempre la barra de tareas en la parte inferior, mantén pulsada la línea divisoria"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"El producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> y los <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tareas visible"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tareas oculta"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Ver siempre Barra de Tareas"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de Barra de Tareas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 93fbd1c..bffce79 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sule kõik"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pühkige kindlasti parem- või vasakpoolsest servast"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pühkige ekraani paremast või vasakust servast keskele ja eemaldage sõrm"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Õppisite, kuidas tagasiliikumiseks paremalt pühkida. Nüüd vaadake, kuidas rakenduste vahel vahetada."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Tegite tagasiliikumise liigutuse. Järgmisena vaadake, kuidas rakenduste vahel vahetada."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Tegite tagasiliikumise liigutuse"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veenduge, et te ei pühiks liiga ekraani allosa lähedalt."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Tagasiliigutuse tundlikkuse muutmiseks avage menüü Seaded"</string>
@@ -94,10 +97,12 @@
     <string name="action_share" msgid="2648470652637092375">"Jaga"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
     <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Jagatud ekraanikuva valikust väljumine"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus"</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"Vidinaid praegu ei toetata, valige mõni muu rakendus"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Hankige oma rutiini põhjal rakenduste soovitusi"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Tegumiriba kinnitamiseks vajutage pikalt jagajat"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tehke tegumiriba abil enamat"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Alati kuvatud tegumiriba"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Puudutage pikalt jaoturit, et tegumiriba oleks ekraani allosas alati kuvatud"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Puudutage pikalt toiminguklahvi, et ekraanil kuvatut otsida"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"See toode kasutab otsingu jaoks ekraani valitud osa. Kehtivad Google\'i <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privaatsuseeskirjad<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ja <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>teenusetingimused<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sule"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Avaleht"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Tegumiriba on kuvatud"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Tegumiriba on peidetud"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigeerimisriba"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Kuva tööriistariba alati"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Kuva tegumiriba alati"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigeerimisrežiimi muutmine"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tegumiriba jagaja"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 53b3390..39fc489 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Garbitu guztiak"</string>
@@ -31,10 +33,10 @@
     <string name="time_left_for_app" msgid="3111996412933644358">"<xliff:g id="TIME">%1$s</xliff:g> gelditzen dira gaur"</string>
     <string name="title_app_suggestions" msgid="4185902664111965088">"Aplikazioen iradokizunak"</string>
     <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Iradokitako aplikazioak"</string>
-    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Jaso aplikazioen iradokizunak hasierako pantailaren beheko errenkadan"</string>
-    <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Jaso aplikazioen iradokizunak hasierako pantailako gogokoen errenkadan"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Atzitu erraz aplikazio erabilienak hasierako pantailatik bertatik. Ohituren arabera aldatuko dira iradokizunak. Hasierako pantailara eramango dira beheko errenkadan dauden aplikazioak."</string>
-    <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Atzitu erraz aplikazio erabilienak hasierako pantailatik bertatik. Ohituren arabera aldatuko dira iradokizunak. Gogokoen errenkadako aplikazioak hasierako pantailara eramango ditugu."</string>
+    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Jaso aplikazioen iradokizunak orri nagusiaren beheko errenkadan"</string>
+    <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Jaso aplikazioen iradokizunak orri nagusiko gogokoen errenkadan"</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Atzitu erraz aplikazio erabilienak orri nagusitik bertatik. Ohituren arabera aldatuko dira iradokizunak. Orri nagusira eramango dira beheko errenkadan dauden aplikazioak."</string>
+    <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Atzitu erraz aplikazio erabilienak orri nagusitik bertatik. Ohituren arabera aldatuko dira iradokizunak. Gogokoen errenkadako aplikazioak orri nagusira eramango ditugu."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Jaso aplikazioen iradokizunak"</string>
     <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Ez, eskerrik asko"</string>
     <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Ezarpenak"</string>
@@ -48,7 +50,8 @@
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Keinu bidezko nabigazioaren tutoriala osatzeko, biratu gailua"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik hasten zarela pasatzen"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik erdialdera pasatzen duzula eta ondoren hatza jasotzen duzula"</string>
-    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Hatza eskuinetik pasatuta atzera egiten ikasi duzu. Jarraian, ikasi aplikazioa aldatzen."</string>
+    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Hatza eskuinetik pasatuta atzera egiten ikasi duzu. Jarraian, lortu aplikazioz aldatzeko argibideak."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ikasi duzu atzera egiteko keinua. Jarraian, lortu aplikazioz aldatzeko argibideak."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ikasi duzu atzera egiteko keinua"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ziurtatu hatza ez duzula pasatzen pantailaren behealdetik gertuegi"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Keinuaren sentikortasuna aldatzeko, joan ezarpenetara"</string>
@@ -60,12 +63,12 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ziurtatu ez duzula mugimendua gelditzen askatu arte"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Ziurtatu hatza zuzen pasatzen duzula gora"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Ikasi duzu hasierako pantailara joateko keinua. Orain, ikasi atzera egiten."</string>
-    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Ikasi duzu hasierako pantailara joateko keinua"</string>
-    <string name="home_gesture_intro_title" msgid="836590312858441830">"Pasatu hatza hasierako pantailara joateko"</string>
-    <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pasatu hatza pantailaren behealdetik gora. Keinu horrek hasierako pantailara eramango zaitu beti."</string>
-    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pasatu bi hatz pantailaren behealdetik gora. Hasierako pantailara eramango zaitu beti keinu horrek."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Joan hasierako pantailara"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Ikasi duzu orri nagusira joateko keinua. Orain, ikasi atzera egiten."</string>
+    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Ikasi duzu orri nagusira joateko keinua"</string>
+    <string name="home_gesture_intro_title" msgid="836590312858441830">"Pasatu hatza orri nagusira joateko"</string>
+    <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pasatu hatza pantailaren behealdetik gora. Keinu horrek orri nagusira eramango zaitu beti."</string>
+    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pasatu bi hatz pantailaren behealdetik gora. Orri nagusira eramango zaitu beti keinu horrek."</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Joan orri nagusira"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Pasatu hatza pantailaren behealdetik gora"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Bikain!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula"</string>
@@ -86,15 +89,17 @@
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Ederki!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriala: <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Dena prest!"</string>
-    <string name="allset_hint" msgid="459504134589971527">"Pasatu hatza gora hasierako pantailara joateko"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Hasierako pantailara joateko, sakatu Hasiera botoia"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Pasatu hatza gora orri nagusira joateko"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Orri nagusira joateko, sakatu Hasiera botoia"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Prest zaude <xliff:g id="DEVICE">%1$s</xliff:g> erabiltzen hasteko"</string>
     <string name="default_device_name" msgid="6660656727127422487">"gailua"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Sisteman nabigatzeko ezarpenak"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Partekatu"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
     <string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Gorde aplikazio parea"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pantaila zatitua erabiltzeko, aukeratu beste aplikazio bat"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Utzi"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Irten pantaila zatituaren hautapenetik"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitzeko, aukeratu beste aplikazio bat"</string>
@@ -107,10 +112,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Biratu pantaila"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Zereginen barra erabiltzeko argibideak"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Bi aplikazio batera erabiltzeko, arrastatu bat albo batera"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Zereginen barra ikusteko, pasatu hatza gora poliki"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Zereginen barra ikusteko, pasatu hatza gora mantso"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Jaso aplikazioen iradokizunak erabileran oinarrituta"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Zereginen barra ainguratzeko, sakatu zatitzailea luze"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Egin gauza gehiago zereginen barrarekin"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Erakutsi beti zereginen barra"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pantailaren behealdeko zereginen barra beti erakusteko, eduki sakatuta zatitzailea"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Eduki sakatuta ekintza-tekla pantailan dagoena bilatzeko"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produktu honek pantailan hautatutako zatia erabiltzen du bilaketa egiteko. Google-ren <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Pribatutasun-gidalerroak<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> eta <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Zerbitzu-baldintzak<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> aplikatzen dira."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Eginda"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hasiera"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index c8da620..a3e5b7f 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,7 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"بدون موارد اخیر"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"رایانه"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"برنامه‌های اخیر"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"دقت کنید که از انتهای لبه سمت راست یا سمت چپ تند بکشید"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"دقت کنید که از لبه سمت راست یا سمت چپ تند به وسط صفحه بکشید و رها کنید"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"یاد گرفتید چگونه برای رفتن به عقب از سمت راست تند بکشید. مورد بعدی، با نحوه جابه‌جا شدن بین برنامه‌ها آشنا شوید."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"اشاره برگشتن را تکمیل کردید. مورد بعدی، با نحوه جابه‌جا شدن بین برنامه‌ها آشنا شوید."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"اشاره برگشتن را تکمیل کردید"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"دقت کنید که موقع تند کشیدن، بیش‌از حد به پایین صفحه نزدیک نشوید"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"برای تغییر حساسیت اشاره برگشت، به «تنظیمات» بروید"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"هم‌رسانی"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
     <string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ذخیره جفت برنامه"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"انتخاب برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"لغو کردن"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"خروج از انتخاب صفحهٔ دونیمه"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"رد شدن"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"چرخاندن صفحه"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"آموزش نوار وظیفه"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"برای استفاده هم‌زمان از ۲ برنامه، یک برنامه را به کناری بکشید"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"برای استفاده هم‌زمان از ۲ برنامه، یک برنامه را به‌کنار بکشید"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"برای نمایش «نوار وظیفه»، انگشتتان را آهسته به‌بالا بکشید"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"براساس روال‌هایتان، پیشنهاد برنامه دریافت کنید"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"برای سنجاق کردن «نوار وظیفه»، جداکننده را چند ثانیه فشار دهید"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"جداکننده را چند ثانیه فشار دهید تا «نوار وظیفه» سنجاق شود"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"با «نوار وظیفه» می‌توانید کارهای بیشتر انجام دهید"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"همیشه نشان داده شدن «نوار وظیفه»"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"برای اینکه «نوار وظیفه» همیشه در پایین صفحه نشان داده شود، تقسیم‌کننده را لمس کنید و نگه دارید"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"برای جستجوی محتوای صفحه‌نمایش، دکمه کنش را لمس کنید و نگه دارید"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏این محصول از قسمت انتخاب‌شده صفحه‌نمایش شما برای جستجو استفاده می‌کند. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>خط‌مشی رازداری<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> و <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>شرایط خدمات<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google اعمال می‌شود."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تمام"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"صفحه اصلی"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index c8c3490..40c4fc2 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Poista kaikki"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pyyhkäise aivan oikeasta tai vasemmasta reunasta"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pyyhkäise näytön oikeasta tai vasemmasta reunasta keskelle ja päästä irti"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Osaat palata takaisin pyyhkäisemällä oikeasta reunasta. Opettele seuraavaksi vaihtamaan sovellusta."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Olet oppinut Takaisin-eleen. Opettele seuraavaksi vaihtamaan sovellusta."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Olet oppinut takaisin-eleen"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Varo, ettet pyyhkäise liian lähellä alareunaa"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Voit muuttaa Takaisin-eleen herkkyyttä asetuksista"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Jaa"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
     <string name="action_split" msgid="2098009717623550676">"Jaa"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Peruuta"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Poistu jaetun näytön valinnasta"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ohita"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Käännä näyttö"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tehtäväpalkin ohje"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Vedä sovellus sivuun, ja voit käyttää kahta sovellusta"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Vedä sovellus sivuun ja käytä kahta sovellusta"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Näytä tehtäväpalkki pyyhkäisemällä ylös hitaasti"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Sovellussuosituksia käytön perusteella"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Vastaanota sovellussuosituksia käytön perusteella"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Kiinnitä tehtäväpalkki painamalla jakajaa pitkään"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Vinkkejä tehtäväpalkin tehokkaampaan käyttöön"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Näytä tehtäväpalkki aina"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jos haluat tehtäväpalkin näkyvän aina näytön alaosassa, kosketa jakajaa pitkään"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Kosketa toimintonäppäintä pitkään, niin voit tehdä haun näytöltäsi"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Tämä tuote käyttää hakuun näytön valittua osaa. Tähän sovelletaan Googlen <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>tietosuojakäytäntöä<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ja <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>käyttöehtoja<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Etusivu"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 8a8a9aa..10aa359 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assurez-vous de balayer l\'écran à partir de l\'extrémité droite ou gauche"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assurez-vous de balayer l\'écran à partir de l\'extrémité droite ou gauche vers le centre, puis allons-y"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous avez appris à balayer de la droite pour revenir en arrière. Apprenez comment changer d\'appli."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Vous avez appris le geste de retour en arrière. Maintenant, apprenez comment changer d\'application."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Vous avez appris le geste de retour en arrière"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assurez-vous de ne pas balayer trop près du bas de l\'écran"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste de retour dans Paramètres"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Enr. paire d\'applis"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre application pour utiliser l\'Écran divisé"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection d\'écran divisé"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre application pour utiliser l\'écran partagé"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorer"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informations sur la barre des tâches"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Pour utiliser deux applis, faites-les glisser vers le côté"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lent. vers le haut pour afficher la barre des tâches"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Faites glisser une appli sur le côté pour en utiliser deux à la fois"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lentement vers le haut pour voir la barre des tâches"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis en fonction de vos routines"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Maint. doigt sur séparateur pour épingler la barre de tâches"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Maintenez le doigt sur le séparateur pour épingler la barre des tâches"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la Barre des tâches"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la Barre des tâches en bas de l\'écran, maintenez le doigt sur le séparateur"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Maintenez le doigt sur la touche d\'action pour rechercher ce qui se trouve sur votre écran"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ce produit utilise la partie sélectionnée de votre écran pour effectuer une recherche. La <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>politique de confidentialité<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> et les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>conditions d\'utilisation<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google s\'appliquent."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Touj. afficher barre des tâches"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Tjrs afficher barre des tâches"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Changer de mode de navigation"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index df6cad4..457d425 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Veillez à bien balayer l\'écran depuis le bord gauche ou droit"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Balayez bien l\'écran depuis le bord gauche ou droit jusqu\'au centre avant de relever le doigt"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous savez revenir en arrière en balayant depuis la droite. Apprenez à passer d\'une appli à l\'autre."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Vous avez appris le geste pour revenir en arrière. Apprenez ensuite à passer d\'une appli à l\'autre."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Vous avez appris le geste pour revenir en arrière"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veillez à ne pas balayer l\'écran trop près du bas"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste retour dans les paramètres"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Enregistrer la paire d\'applis"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour l\'écran partagé"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Sélectionnez une autre appli pour utiliser l\'écran partagé."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection de l\'écran partagé"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Sélect. autre appli pour utiliser l\'écran partagé"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Fonctionnement de la barre des tâches"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Faites glisser une appli sur le côté pour en utiliser 2 à la fois"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lentement vers haut pour afficher barre des tâches"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Balayez lentement vers le haut pour voir la barre des tâches"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis basées sur vos habitudes"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Appui de manière prolongée sur le séparateur pour épingler la barre des tâches"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Appui prolongé sur le séparateur pour épingler la barre des tâches"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Toujours afficher la barre des tâches"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pour toujours afficher la barre des tâches en bas de votre écran, appuyez sur le séparateur de manière prolongée."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Appuyez de manière prolongée sur la touche d\'action pour rechercher ce qui se trouve à l\'écran"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ce produit utilise la zone sélectionnée de l\'écran pour rechercher. Les <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Règles de confidentialité<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> et les <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Conditions d\'utilisation<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> de Google s\'appliquent."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Accueil"</string>
@@ -124,12 +132,12 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barre des tâches affichée"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barre des tâches masquée"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barre de navigation"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Toujours voir barre des tâches"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Barre des tâches tjs visible"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Modifier le mode de navigation"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de barre des tâches"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autre applis.}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Ajout de l\'appli au bureau"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Annuler"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 2022573..0be8958 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Borrar todo"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo ata o medio da pantalla e levantalo"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendiches a pasar o dedo desde a dereita para volver. Agora, aprende a cambiar de aplicación."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Completaches o xesto de volver á última pantalla. O próximo é aprender a cambiar de aplicación."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Completaches o xesto de volver á última pantalla"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Asegúrate de non pasar o dedo demasiado preto da parte inferior da pantalla"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Podes cambiar a sensibilidade do xesto en Configuración"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar parella apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saír da selección de pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrastra unha aplicación cara a un lado para usar dúas á vez"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Pasa o dedo amodo cara arriba para ver a barra de tarefas"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén suxestións de aplicacións en función da túa rutina"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén premida a liña divisoria para fixar a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén premida a liña divisoria para fixar a barra de tarefas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Tira máis proveito da barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar sempre a barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para fixar a barra de tarefas na parte inferior, mantén premida a liña divisoria"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén premida a tecla de acción para buscar o que hai na pantalla"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este produto utiliza a parte seleccionada da pantalla para facer buscas. Aplícanse as <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Condicións de servizo<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> e a <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> de Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Estase mostrando a barra de tarefas"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Non se está mostrando a barra de tarefas"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegación"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Manter Barra de tarefas"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre a barra de tarefas"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar modo de navegación"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index d1adf5c..644240a 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"બધું સાફ કરો"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ખાતરી કરો કે તમે એકદમ દૂરની જમણી કે ડાબી કિનારીએથી સ્વાઇપ કરો છો"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ખાતરી કરો કે તમે જમણી કે ડાબી કિનારીએથી સ્ક્રીનના મધ્ય ભાગ સુધી સ્વાઇપ કરો છો અને આંગળી ઊંચકી લો છો"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"પાછળ જવા જમણેથી કેવી રીતે સ્વાઇપ કરવું એ તમે શીખી લીધું છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત જાણો."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત વિશે જાણો."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ખાતરી કરો કે તમારાથી સ્ક્રીનની એકદમ નીચેની કિનારીની ખૂબ નજીક સુધી સ્વાઇપ ન થઈ જાય"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"પાછા જવાના સંકેતની સંવેદિતા બદલવા માટે, સેટિંગમાં જાઓ"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"શેર કરો"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
     <string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ઍપની જોડી સાચવો"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"વિભાજિત સ્ક્રીનની સુવિધાનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"રદ કરો"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"\'સ્ક્રીનને વિભાજિત કરો\' પસંદગીમાંથી બહાર નીકળો"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"તમારા રૂટિનના આધારે ઍપના સુઝાવો મેળવો"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ટાસ્કબારને પિન કરવા માટે, વિભાજકને થોડીવાર દબાવી રાખો"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ટાસ્કબાર વડે બીજું ઘણું કરો"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ટાસ્કબાર હંમેશાં બતાવો"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ટાસ્કબાર હંમેશાં તમારી સ્ક્રીનમાં સૌથી નીચે દેખાય તે માટે વિભાજકને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"તમારી સ્ક્રીન પર જે હોય તે શોધવા માટે, ઍક્શન કી ટચ કરીને દબાવી રાખો"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"શોધવા માટે, આ પ્રોડક્ટ તમારી સ્ક્રીનના પસંદ કરેલા ભાગનો ઉપયોગ કરે છે. Googleની <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>પ્રાઇવસી પૉલિસી<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> અને <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>સેવાની શરતો<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> લાગુ થાય છે."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"બંધ કરો"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"થઈ ગયું"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"હોમ"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 5ebe814..b2da5db 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -21,9 +21,11 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करें"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"हाल ही में इस्तेमाल किया गया कोई ऐप्लिकेशन नहीं है"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
+    <string name="recents_empty_message" msgid="7040467240571714191">"हाल ही का कोई आइटम नहीं है"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
-    <string name="recents_clear_all" msgid="5328176793634888831">"सभी ऐप्लिकेशन बंद करें"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"सभी हटाएं"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"हाल ही में इस्तेमाल किए गए ऐप्लिकेशन"</string>
     <string name="task_view_closed" msgid="9170038230110856166">"टास्क बंद किया गया"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रीन पर बिलकुल दाएं या बाएं किनारे से स्वाइप करें"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रीन पर दाएं या बाएं किनारे से बीच तक स्वाइप करें और फिर अपनी उंगली को स्क्रीन से हटा दें"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"आपने पीछे ले जाने वाले हाथ के जेस्चर के बारे में जान लिया है. एक ऐप से दूसरे पर जाने का तरीका जानें."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके पिछली स्क्रीन पर वापस कैसे जाएं"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"स्क्रीन पर बिलकुल नीचे तक स्वाइप न करें"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'सेटिंग\' में जाकर, पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) की संवेदनशीलता बदलें"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर सेव करें"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन इस्तेमाल करने के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"अभी नहीं"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रीन मोड से बाहर निकलें"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
@@ -107,10 +112,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन घुमाएं"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"टास्कबार का ट्यूटोरियल"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"किसी ऐप को किनारे की ओर ड्रैग करके 2 ऐप एक साथ इस्तेमाल करें"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"टास्कबार दिखाने के लिए, ऊपर की ओर धीरे से स्वाइप करें"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"डिवाइस के इस्तेमाल के आधार पर ऐप्लिकेशन के सुझाव पाएं"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"टास्कबार देखने के लिए, ऊपर की ओर धीरे से स्वाइप करें"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"इस्तेमाल के आधार पर ऐप्लिकेशन के सुझाव पाएं"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार को पिन करने के लिए डिवाइडर को दबाकर रखें"</string>
-    <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार की मदद से कई और काम करें"</string>
+    <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार के साथ कई और काम करें"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार को हमेशा दिखाएं"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार को हमेशा अपनी स्क्रीन के नीचे दिखाने के लिए, डिवाइडर दबाकर रखें"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"स्क्रीन में दिख रहे कॉन्टेंट को खोजने के लिए, ऐक्शन बटन को दबाकर रखें"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यह प्रॉडक्ट, कॉन्टेंट खोजने के लिए स्क्रीन पर चुनिंदा हिस्से का इस्तेमाल करता है. Google की <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>निजता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> और <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवा की शर्तें<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू होती हैं."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"हो गया"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index ad0be8e..b68d961 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Izbriši sve"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite da prijeđete prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvršili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Izvršili ste pokret za povratak"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite da ne prijeđete prstom preblizu dnu zaslona"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osjetljivost pokreta povratka promijenite u postavkama"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Podijeli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Spremi par apl."</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Odustani"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zatvori odabir podijeljenog zaslona"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za upotrebu podijeljenog zaslona"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Primajte prijedloge aplikacija na temelju svoje rutine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dugo pritisnite razdjelnik da biste prikvačili alatnu traku"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Učinite više pomoću trake sa zadacima"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Uvijek prikazuj traku sa zadacima"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Da bi se traka prikazivala, dodirnite i držite razdjelnik"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Dodirnite i zadržite tipku za radnju da biste pretražili što se nalazi na zaslonu"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ovaj proizvod upotrebljava odabrani dio zaslona za pretraživanje. Primjenjuju se Googleova <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravila o privatnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>uvjeti pružanja usluge<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
@@ -129,7 +138,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži više aplikacija (još #).}one{Prikaži više aplikacija (još #).}few{Prikaži više aplikacija (još #).}other{Prikaži više aplikacija (još #).}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Odustani"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index b1298ce..006184b 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Csúsztasson a képernyő jobb vagy bal széléről."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Csúsztassa ujját a képernyő jobb vagy bal széléről a képernyő közepéig, majd emelje fel."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Megtanulta, hogyan léphet vissza jobbról csúsztatva. A következő az appok közötti váltás."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Teljesítette a visszalépési kézmozdulatot. Most megtanulhatja, hogyan válthat az appok között."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Teljesítette a visszalépési kézmozdulatot."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ne csúsztasson túl közel a képernyő aljához."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"A vissza mozdulat érzékenysége a Beállításokban módosítható"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Megosztás"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
     <string name="action_split" msgid="2098009717623550676">"Felosztás"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"App-pár mentése"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Válasszon másik appot a képernyő felosztásához"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Mégse"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Kilépés az osztott képernyő elemeinek kiválasztásából"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Válasszon másik appot a képernyő felosztásához"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Alkalmazásjavaslatokat kaphat a rutinja alapján"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"A Feladatsáv kitűzéséhez nyomja meg hosszan az elválasztót"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Jobban kihasználhatja a Feladatsávot"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mindig jelenjen meg a Feladatsáv"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ahhoz, hogy a Feladatsáv mindig megjelenjen a képernyő alján, érintse meg és tartsa lenyomva az elválasztót"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"A műveletbillentyűt lenyomva tartva kereshet a képernyőn található tartalmak között"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ez a termék a képernyő kiválasztott részét használja a kereséshez. A Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Adatvédelmi irányelvei<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> és <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Általános Szerződési Feltételei<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> érvényesek."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Bezárás"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kész"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Kezdőlap"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Feladatsáv megjelenítve"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Feladatsáv elrejtve"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigációs sáv"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Mindig megjelenő feladatsáv"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Mindig megjelenő Feladatsáv"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigációs mód módosítása"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Feladatsáv-elválasztó"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index d896b51..e0646aa 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -21,7 +21,9 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"Վերջին տարրեր չկան"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
+    <string name="recents_empty_message" msgid="7040467240571714191">"Այստեղ դեռ ոչինչ չկա"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Փակել բոլորը"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"Վերջին հավելվածներ"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Համոզվեք, որ մատը սահեցնում եք էկրանի աջ կամ ձախ եզրից"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Մատը սահեցրեք էկրանի աջ կամ ձախ եզրից դեպի կենտրոն և բաց թողեք"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Դուք սովորեցիք՝ ինչպես մատը աջից սահեցնելով հետ գնալ։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսը։"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Դուք սովորեցիք հետ գնալու ժեստը։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսը։"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Դուք սովորեցիք հետ գնալու ժեստը"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Համոզվեք, որ մատը չափազանց մոտ չեք սահեցնում էկրանի ներքևի հատվածին"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Հետ գնալու ժեստի զգայունությունը փոփոխեք կարգավորումներում"</string>
@@ -94,10 +97,12 @@
     <string name="action_share" msgid="2648470652637092375">"Կիսվել"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
     <string name="action_split" msgid="2098009717623550676">"Տրոհել"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Պահել հավելվ․ զույգը"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Հպեք այլ հավելվածի՝ տրոհված էկրանից օգտվելու համար"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ընտրեք այլ հավելված՝ տրոհված էկրանից օգտվելու համար"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Չեղարկել"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Դուրս գալ տրոհված էկրանի ռեժիմից"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ընտրեք այլ հավելված՝ կիսված էկրանից օգտվելու համար"</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ընտրեք այլ հավելված՝ տրոհված էկրանից օգտվելու համար"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"Վիջեթները ներկայումս չեն աջակցվում. ընտրեք այլ հավելված"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Բաց թողնե՞լ նավիգացիայի ուղեցույցը"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Ստացեք առաջարկներ ձեր գործողությունների հիման վրա"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Հավելվածների վահանակն ամրացնելու համար երկար սեղմեք բաժանարարի վրա"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Օգտվեք հավելվածների վահանակի բոլոր հնարավորություններից"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ամրացրեք հավելվածների վահանակը"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Հավելվածների վահանակն էկրանի ներքևում ամրացնելու համար հպեք և պահեք բաժանիչը"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Սեղմած պահեք գործողության ստեղնը՝ էկրանին բովանդակություն որոնելու համար"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Այս պրոդուկտն օգտագործում է էկրանի ընտրված հատվածը որոնման համար։ Կիրառվում են Google-ի <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>գաղտնիության քաղաքականությունը<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> և <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>օգտագործման պայմանները<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>։"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Պատրաստ է"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Սկիզբ"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Խնդրագոտին ցուցադրվում է"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Խնդրագոտին թաքցված է"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Նավիգացիայի գոտի"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Միշտ ցուցադրել հավելվածները"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Միշտ ցույց տալ վահանակը"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Փոխել նավիգացիայի ռեժիմը"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Հավելվածների վահանակի բաժանիչ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index e6563ae..34a8b2b 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pastikan Anda menggeser dari tepi ujung kanan atau ujung kiri"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pastikan Anda menggeser dari tepi kanan atau kiri ke tengah layar, lalu lepaskan"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Anda telah belajar cara geser dari kanan untuk kembali. Berikutnya, pelajari cara beralih aplikasi."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Anda telah menyelesaikan gestur kembali. Selanjutnya, pelajari cara beralih aplikasi."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah menyelesaikan gestur kembali"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pastikan Anda tidak menggeser terlalu dekat ke bagian bawah layar"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Untuk mengubah sensitivitas gestur kembali, buka Setelan"</string>
@@ -94,10 +96,12 @@
     <string name="action_share" msgid="2648470652637092375">"Bagikan"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Pisahkan"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Simpan pasangan apl"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk aplikasi lain untuk memakai layar terpisah"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar dari pemilihan layar terpisah"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk memakai layar terpisah"</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk dibuka di layar terpisah"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"Widget saat ini tidak didukung, pilih aplikasi lain"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Lewati tutorial gestur?"</string>
@@ -110,7 +114,11 @@
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Geser perlahan ke atas untuk menampilkan Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dapatkan saran aplikasi berdasarkan rutinitas Anda"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Tekan lama pemisah untuk menyematkan Taskbar"</string>
-    <string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak dengan Taskbar"</string>
+    <string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak hal dengan Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Selalu tampilkan Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk selalu menampilkan Taskbar di bagian bawah layar Anda, sentuh &amp; tahan pembatasnya"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh &amp; tahan tombol tindakan untuk mencari konten di layar Anda"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bagian layar terpilih untuk menelusuri. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Kebijakan Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Persyaratan Layanan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google berlaku."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Layar utama"</string>
@@ -129,7 +137,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lain.}other{Tampilkan # aplikasi lain.}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan aplikasi ke Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batalkan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index c297a6b..d5f2488 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar að miðju skjásins og sleppa síðan"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Þú lærðir að strjúka frá hægri til að bakka. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Þú laukst við að kynna þér bendinguna „til baka“. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Þú laukst við að kynna þér bendinguna „til baka“"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Passaðu að strjúka ekki of nálægt neðri brún skjásins"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Til að breyta næmi til baka-bendingar ferðu í stillingar"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Deila"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
     <string name="action_split" msgid="2098009717623550676">"Skipta"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Vista forritapar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Veldu annað forrit til að nota skjáskiptingu"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Hætta við"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Loka skjáskiptingu"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Veldu annað forrit til að nota skjáskiptingu"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Fáðu forritatillögur sem byggjast á rútínunni þinni"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Haltu skiptingu forritastikunnar inni til að festa hana"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Nýttu forritastikuna betur"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Halda forritastikunni sýnilegri"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Haltu skjáskiptingunni neðst á skjánum inni til að halda forritastikunni sýnilegri"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Haltu aðgerðalyklinum inni til að leita að því sem er á skjánum"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Þessi vara notar valinn hluta skjásins til að leita. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Persónuverndarstefna<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>þjónustuskilmálar<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google gilda."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Loka"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Lokið"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Heim"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index c028d26..c38243f 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assicurati di scorrere dal bordo all\'estrema destra o all\'estrema sinistra"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assicurati di scorrere dal bordo destro o sinistro verso il centro dello schermo e solleva il dito"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Hai imparato a scorrere da destra per tornare indietro. Ora impara come passare da un\'app all\'altra."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Hai completato il gesto Indietro. Ora, impara come passare da un\'app all\'altra."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Hai completato il gesto Indietro"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assicurati di non scorrere troppo vicino alla parte inferiore dello schermo"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Usa Impostazioni per cambiare sensibilità del gesto Indietro"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Condividi"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividi"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Salva coppia di app"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Scegli un\'altra app per usare lo schermo diviso"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annulla"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Esci dalla selezione dello schermo diviso"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Scegli un\'altra app per usare lo schermo diviso"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Visualizza le app suggerite in base alla tua routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Premi a lungo sul divisore per fissare la barra delle app"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Fai di più con la barra delle app"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la barra delle app"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Per mostrare sempre la barra delle app in basso, tocca e tieni premuto il divisore"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Tocca e tieni premuto il tasto azione per cercare gli elementi sullo schermo"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Il prodotto usa la parte selezionata dello schermo per cercare. Si applicano le <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Norme sulla privacy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termini di servizio<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> di Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fine"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra delle app visualizzata"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra delle app nascosta"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra di navigazione"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Mostra sempre barra delle app"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Mostra sempre barra app"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Cambia modalità di navigazione"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisore barra delle app"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 505096b..9d6b246 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"חשוב להחליק מהקצה השמאלי או הימני"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"חשוב להחליק מהקצה השמאלי או הימני למרכז המסך ואז לשחרר"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"למדת איך להחליק מצד ימין כדי לחזור אחורה. בשלב הבא לומדים איך לעבור בין אפליקציות."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"השלמת את תנועת \'הקודם\'. בשלב הבא לומדים איך לעבור בין אפליקציות."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"השלמת את התנועה \'חזרה אחורה\'"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"חשוב שלא להחליק קרוב מדי לתחתית המסך"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"כדי לשנות את מידת הרגישות של תנועת החזרה, יש לעבור להגדרות"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"שיתוף"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
     <string name="action_split" msgid="2098009717623550676">"פיצול"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"שמירת צמד אפליקציות"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ביטול"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"יציאה מתצוגת מסך מפוצל"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"כדי להשתמש במסך מפוצל צריך לבחור אפליקציה אחרת"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"סיבוב המסך"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"הסבר על סרגל האפליקציות"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור אפליקציה לצד"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"צריך להחליק לאט כדי להציג את סרגל האפליקציות"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"קבלת הצעות לאפליקציות על סמך השימוש השגרתי שלך"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"צריך להחליק לאט למעלה כדי להציג את סרגל האפליקציות"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"אפשר לקבל הצעות לאפליקציות על סמך השימוש השגרתי שלך"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"כדי להצמיד את סרגל האפליקציות, לוחצים לחיצה ארוכה על המחיצה"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"פעולות נוספות שאפשר לעשות עם סרגל האפליקציות"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"תמיד להציג את סרגל האפליקציות"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"כדי להציג תמיד את סרגל האפליקציות בתחתית המסך, יש ללחוץ לחיצה ארוכה על המחיצה"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"כדי לחפש במסך, צריך ללחוץ לחיצה ארוכה על מקש הפעולה"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏המוצר הזה משתמש בחלק שבחרת במסך לצורך חיפוש, בכפוף ל<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>מדיניות הפרטיות<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ו<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>התנאים וההגבלות<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> של Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"סיום"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"בית"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index e9f1670..69b3954 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"パソコン"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"右端または左端からスワイプしてください"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"画面の右端または左端から中央に向かってスワイプし、指を離してください"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"「戻る」操作を完了しました。次は、アプリを切り替える方法を覚えましょう。"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"「戻る」操作を学習しました"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"スワイプする際は画面の下部に近づきすぎないようにしましょう"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"「戻る」操作の感度を変更するには [設定] に移動します"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"共有"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"アプリのペア設定保存"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"分割画面を使用するには、他のアプリをタップします"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"分割画面を使用するには別のアプリを選択してください"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"キャンセル"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"分割画面の選択を終了します"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"分割画面にするには、別のアプリを選択してください"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"画面を回転"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"タスクバーの説明"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"アプリを横にドラッグして 2 個のアプリを同時に使用できます"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"アプリを横にドラッグすると 2 個のアプリを同時に使用できます"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"タスクバーを表示するには、上にゆっくりとスワイプします"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"毎日の使用状況に基づいてアプリの候補が表示されます"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"タスクバーを固定するには分割線を長押ししてください"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"分割線を長押ししてタスクバーを固定します"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"タスクバーの各種機能"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"タスクバーを常に表示"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"タスクバーを画面下部に常に表示するには分割線を長押しします"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"画面上の内容を検索するには、アクションキーを長押ししてください"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"このサービスは、検索する際に画面上で選択された箇所を使用します。Google の<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>プライバシー ポリシー<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>と<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>利用規約<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>が適用されます。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完了"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ホーム"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"タスクバー表示"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"タスクバー非表示"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"ナビゲーション バー"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"常にタスクバーを表示"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"常にタスクバーを表示する"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ナビゲーション モードを変更"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"タスクバーの区切り"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 5bcf856..4306f1f 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"დესკტოპი"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"გადაფურცლეთ უკიდურესი მარჯვენა ან მარცხენა ბოლოდან"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"გადაფურცლეთ მარჯვენა ან მარცხენა კიდიდან ეკრანის ცენტრისკენ და თითი აუშვით"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"თქვენ ისწავლეთ მარჯვნიდან გადაფურცვლა უკან დასაბრუნებლად. ახლა კი შეიტყვეთ, როგორ გადართოთ აპები."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი. ახლა კი შევიტყოთ, როგორ გადავრთოთ აპები."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"არ გადაფურცლოთ ეკრანის ბოლოსთან ახლოს"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"დაბრუნების ჟესტის მგრძნობელობის შესაცვლელად გადადით პარამეტრებზე"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"გაზიარება"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string>
     <string name="action_split" msgid="2098009717623550676">"გაყოფა"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"აპთა წყვილის შენახვა"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"გაუქმება"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ეკრანის გაყოფის არჩევანიდან გასვლა"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"აირჩიეთ სხვა აპი ეკრანის გასაყოფად"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"მიიღეთ აპის შეთავაზებები თქვენი რუტინის მიხედვით"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ხანგრძლივად დააჭირეთ გამყოფს ამოცანათა ზოლის ჩასამაგრებლად"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"გააკეთეთ მეტი ამოცანათა ზოლის მეშვეობით"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ამოცანათა ზოლის მუდმივად ჩვენება"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"თქვენი ეკრანის ქვედა ნაწილში ამოცანათა ზოლის მუდმივად საჩვენებლად, ხანგრძლივად შეეხეთ გამყოფს"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"შეეხეთ და გეჭიროთ მოქმედების კლავიში, რათა მოძებნოთ ის, რაც თქვენს ეკრანზეა"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ეს პროდუქტი ძიებისთვის იყენებს თქვენი ეკრანის არჩეულ ნაწილს. მოქმედებს Google-ის <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>კონფიდენციალურობის დებულება<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> და <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>მომსახურებს პირობები<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"მზადაა"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"მთავარი"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index da3670e..2a12452 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Барлығын өшіру"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Экранның оң немесе сол жиегінен сырғытыңыз."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Экранның оң немесе сол жиегінен ортасына қарай сырғытып, саусағыңызды жіберіңіз."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Оңнан солға сырғыту арқылы артқа қайтуды үйрендіңіз. Енді қолданбаларды ауыстыруды үйреніңіз."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Артқа қайту қимылын аяқтадыңыз. Енді қолданбаларды ауыстыруды үйреніңіз."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Артқа қайту қимылын аяқтадыңыз."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Сырғытқанда саусақты экранның төменгі жағына қатты жақындатпаңыз."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Артқа қайту қимылы сезгіштігін параметрлерден өзгертіңіз."</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Бөлісу"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Қолданбаларды жұптауды сақтау"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Бас тарту"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Экранды бөлу режимінен шығу"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 қолданбаны бір мезгілде пайдалану үшін қолданбаны шетке сүйреңіз."</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Тапсырмалар жолағын көрсету үшін жоғары қарай ақырын сырғытыңыз."</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Іс-әрекеттеріңізге негізделген қолданба ұсыныстарын алыңыз."</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапсырмалар жолағын бекіту үшін бөлгішті ұзақ басып тұрыңыз"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапсырмалар жолағын бекіту үшін бөлгішті ұзақ басып тұрыңыз."</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапсырмалар жолағын әрдайым көрсету"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Экранның төменгі жағында тапсырмалар жолағы әрдайым көрсетілуі үшін, бөлгішті басып тұрыңыз."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бұл өнім іздеу үшін экранның таңдалған бөлігін пайдаланады. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Құпиялық саясаты<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> мен <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Қызмет көрсету шарттары<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> қолданылады."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Негізгі экран"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 4c3d732..bcec955 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"កុំព្យូទ័រ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់​ការប្រើប្រាស់​កម្មវិធី"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"សម្អាត​ទាំងអស់"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ត្រូវប្រាកដថា​អ្នកអូសពី​គែមខាងស្ដាំ ឬ​ខាងឆ្វេង"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ត្រូវប្រាកដថា​អ្នកអូសពី​គែមខាងស្ដាំ ឬខាងឆ្វេង​ទៅផ្នែកកណ្ដាល​នៃអេក្រង់ រួច​ដកដៃ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"អ្នកបានស្វែងយល់ពីរបៀបអូសពីខាងស្ដាំ ដើម្បីថយក្រោយ។ បន្ទាប់​ទៀត សូមស្វែងយល់​ពីរបៀប​ប្ដូរកម្មវិធី​។"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"អ្នក​បានបញ្ចប់​ចលនា​ថយក្រោយ​ហើយ។ បន្ទាប់​មកទៀត សូមស្វែងយល់​ពីរបៀប​ប្ដូរកម្មវិធី​។"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"អ្នក​បានបញ្ចប់​ចលនា​ថយក្រោយ​ហើយ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ត្រូវប្រាកដថា​អ្នកមិនអូស​ទៅជិត​ផ្នែកខាងក្រោម​នៃអេក្រង់ពេក"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ដើម្បីប្ដូរកម្រិត​រំញោចនឹង​ចលនាថយក្រោយ សូមចូលទៅកាន់​ការកំណត់"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
     <string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"រក្សាទុកគូកម្មវិធី"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធី​ផ្សេងទៀត ដើម្បីប្រើ​មុខងារបំបែកអេក្រង់"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារ​បំបែកអេក្រង់"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"បោះបង់"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ចាកចេញពីការជ្រើសរើសរបស់មុខងារ​បំបែកអេក្រង់"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារ​បំបែកអេក្រង់"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ទទួលការណែនាំកម្មវិធីដោយផ្អែកលើទម្លាប់របស់អ្នក"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ចុចឱ្យយូរនៅលើបន្ទាត់ខណ្ឌចែក ដើម្បីខ្ទាស់របារកិច្ចការ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ធ្វើបានកាន់តែច្រើនដោយប្រើរបារកិច្ចការ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ដើម្បីបង្ហាញរបារកិច្ចការនៅផ្នែកខាងក្រោមនៃអេក្រង់របស់អ្នកជានិច្ច សូមចុចបន្ទាត់ខណ្ឌចែកឱ្យជាប់"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ចុចគ្រាប់ចុចសកម្មភាពឱ្យជាប់ ដើម្បីស្វែងរកអ្វីដែលមាននៅលើអេក្រង់របស់អ្នក"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ផលិតផលនេះប្រើប្រាស់ផ្នែកដែលបានជ្រើសរើសនៃអេក្រង់របស់អ្នក ដើម្បីស្វែងរក។ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>គោលការណ៍​ឯកជនភាព<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> និង<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>លក្ខខណ្ឌ​ប្រើប្រាស់<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>របស់ Google ត្រូវបានអនុវត្ត។"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"រួចរាល់"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ទំព័រដើម"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index c8efb7e..4df7f3a 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್‌ಟಾಪ್"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್‌ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ನೀವು ಬಲಕೊನೆಯ ಅಂಚಿನಿಂದ ಅಥವಾ ಎಡಕೊನೆಯ ಅಂಚಿನಿಂದ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ನೀವು ಬಲ ಅಥವಾ ಎಡ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್‌ನ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಂಡು ಬಿಟ್ಟುಬಿಡಿ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ಹಿಂದೆ ಹೋಗಲು ಬಲದಿಂದ ಸ್ವೈಪ್ ಮಾಡುವುದು ಹೇಗೆಂದು ಕಲಿತಿರಿ. ಮುಂದೆ, ಆ್ಯಪ್‌ಗಳನ್ನು ಬದಲಿಸುವುದು ಹೇಗೆಂದು ತಿಳಿಯಿರಿ."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಆ್ಯಪ್‌ಗಳನ್ನು ಬದಲಾಯಿಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ನೀವು ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗಕ್ಕೆ ಹೆಚ್ಚು ಹತ್ತಿರ ಸ್ವೈಪ್ ಮಾಡದಂತೆ ನೋಡಿಕೊಳ್ಳಿ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್‌ನ ಸೂಕ್ಷ್ಮತೆ ಬದಲಾಯಿಸಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
     <string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ಸ್ಪ್ಲಿಟ್‌ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಇನ್ನೊಂದು ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ರದ್ದುಮಾಡಿ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಆಯ್ಕೆಯಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"ಸ್ಕ್ರೀನ್ ತಿರುಗಿಸಿ"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ಟಾಸ್ಕ್‌ಬಾರ್ ಶಿಕ್ಷಣ"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ಒಂದೇ ಬಾರಿಗೆ 2 ಆ್ಯಪ್‌ಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್ ಅನ್ನು ಬದಿಗೆ ಎಳೆಯಿರಿ"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ಟಾಸ್ಕ್‌ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು ನಿಧಾನವಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ಟಾಸ್ಕ್‌ಬಾರ್ ಕಾಣುವಂತೆ ಮಾಡಲು ನಿಧಾನವಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ನಿಮ್ಮ ದಿನಚರಿಯ ಆಧಾರದ ಮೇಲೆ ಆ್ಯಪ್ ಸಲಹೆಗಳನ್ನು ಪಡೆಯಿರಿ"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ಟಾಸ್ಕ್ ಬಾರ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲು ಡಿವೈಡರ್ ಮೇಲೆ ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ಟಾಸ್ಕ್‌‌ಬಾರ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲು ಡಿವೈಡರ್ ಮೇಲೆ ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ಟಾಸ್ಕ್‌ಬಾರ್ ಮೂಲಕ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್‌ಬಾರ್ ಅನ್ನು ತೋರಿಸಿ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ಯಾವಾಗಲೂ ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಭಾಗದಲ್ಲಿ ಟಾಸ್ಕ್ ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು, ಡಿವೈಡರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳಿ"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಮೇಲೆ ಏನಿದೆ ಎಂಬುದನ್ನು ಹುಡುಕಲು ಆ್ಯಕ್ಷನ್ ಕೀಯನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ಈ ಉತ್ಪನ್ನವು ಹುಡುಕಲು ನಿಮ್ಮ ಸ್ಕ್ರೀನ್‌ನ ಆಯ್ದ ಭಾಗವನ್ನು ಬಳಸುತ್ತದೆ. Google ನ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ಗೌಪ್ಯತೆ ನೀತಿ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ಮತ್ತು <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ಸೇವಾ ನಿಯಮಗಳು<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ಅನ್ವಯಿಸುತ್ತವೆ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ಆಯಿತು"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ಮುಖಪುಟ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 5b5b728..0fba87d 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"모두 삭제"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"오른쪽 또는 왼쪽 가장자리 끝에서 스와이프하세요."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"오른쪽 또는 왼쪽 가장자리에서 화면 중앙으로 스와이프한 후 손가락을 떼세요."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"오른쪽에서 스와이프하여 뒤로 돌아가는 방법을 배웠습니다. 이번에는 앱 전환 방법을 알아보겠습니다."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"돌아가기 동작을 완료했습니다. 이번에는 앱 전환 방법을 알아보겠습니다."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"돌아가기 동작을 완료했습니다."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"화면 하단에 지나치게 가까운 곳에서 스와이프하면 안 됩니다."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"돌아가기 동작의 민감도를 변경하려면 설정으로 이동하세요"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"공유"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
     <string name="action_split" msgid="2098009717623550676">"분할"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"앱 페어링 저장"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"취소"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"화면 분할 선택 종료"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"앱을 옆으로 드래그하여 앱 2개를 동시에 사용합니다."</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"위로 천천히 스와이프하면 태스크 바가 표시됩니다."</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"사용 습관에 따라 앱 제안을 받습니다."</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"구분선을 길게 눌러 태스크 바 고정하기"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"구분선을 길게 눌러 태스크 바를 고정합니다."</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"태스크 바 최대한 활용하기"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"태스크 바 항상 표시"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"화면 하단에 태스크 바를 항상 표시하려면 구분선을 길게 터치하세요."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"화면 내용을 검색하려면 작업 키 길게 터치"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"이 제품은 사용자가 화면에서 선택한 부분을 사용하여 검색하며, Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>개인정보처리방침<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> 및 <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>서비스 약관<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>이 적용됩니다."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"완료"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"홈"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index ea98e71..061952c 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу параметрлери"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Баарын тазалоо"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Экранды эң четинен оңдон солго же солдон оңго карай сүрүңүз"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Экранды оң же сол жагынан ортосуна карай сүрүп, манжаңызды алыңыз"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Артка кайтуу үчүн экранды оңдон солго карай сүрүүнү үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"\"Артка\" жаңсоосун үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"\"Артка\" жаңсоосун үйрөндүңүз"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Манжаңызды экрандын ылдый жагына өтө жакындатпай сүрүңүз"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн параметрлерге өтүңүз"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Колдонмолорду сактап коюу"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Жокко чыгаруу"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Тандалган экранды бөлүүдөн чыгуу"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткрп жиберүү"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды буруу"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Тапшырмалар тактасы жөнүндө маалымат"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 колдонмону бир убакта пайдалануу үчүн капталга сүйрөңүз"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 колдонмону бир убакта пайдалануу үчүн капталга сүйрөйсүз"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Тапшырмалар тактасын көрүү үчүн экранды жай өйдө сүрүңүз"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Программаңыздын негизинде сунушталган колдонмолорду алуу"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапшырмалар панелин кадап коюу үчүн бөлгүчтү коё бербей басып туруңуз"</string>
-    <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар тактасы менен көбүрөөк нерселерди аткарыңыз"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Аракеттериңизге негизделген сунуштарды алып турасыз"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапшырмалар тактасын кадап коюу үчүн бөлгүчтү коё бербей басып турасыз"</string>
+    <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар тактасы менен көбүрөөк иш бүтүрөсүз"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапшырмалар панелин ар дайым көрсөтүү"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Тапшырмалар панелин экрандын ылдый жагында ар дайым көрсөтүү үчүн бөлгүчтү коё бербей басыңыз"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экрандагы нерсени издөө үчүн аракет баскычын коё бербей кармап туруңуз"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бул кызмат издөө үчүн экранда тандалган бөлүктү колдонот. Google\'дун <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Купуялык эрежелери<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> жана <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Тейлөө шарттары<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> колдонулат."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Бүттү"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Башкы бет"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Тапшырмалар панели көрсөтүлдү"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Тапшырмалар панели жашырылды"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Чабыттоо тилкеси"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Тапшырмалар панелин ар дайым көрсөтүү"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Такта ар дайым көрүнсүн"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Өтүү режимин өзгөртүү"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапшырмалар панелин бөлгүч"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index 2b17b93..e862b9e 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -78,7 +78,8 @@
     <!--  Taskbar 3 button spacing  -->
     <dimen name="taskbar_button_margin_split">88dp</dimen>
     <dimen name="taskbar_button_margin_6_5">219.6dp</dimen>
-    <dimen name="taskbar_contextual_button_margin">48dp</dimen>
+    <dimen name="taskbar_contextual_button_suw_margin">48dp</dimen>
+    <dimen name="taskbar_contextual_button_suw_height">48dp</dimen>
     <dimen name="taskbar_suw_frame">96dp</dimen>
     <dimen name="taskbar_suw_insets">24dp</dimen>
 
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 635523e..9496dd5 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ເດັສທັອບ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາສຸດ ຫຼື ຊ້າຍສຸດ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາ ຫຼື ຊ້າຍໄປຫາທາງກາງຂອງໜ້າຈໍແລ້ວປ່ອຍນິ້ວ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ທ່ານຮຽນຮູ້ວິທີປັດຈາກຂວາເພື່ອກັບຄືນແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ກະລຸນາກວດສອບວ່າທ່ານບໍ່ໄດ້ປັດໃກ້ກັບທາງລຸ່ມຂອງໜ້າຈໍເກີນໄປ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ເພື່ອປ່ຽນຄວາມລະອຽດອ່ອນຂອງທ່າທາງກັບຄືນ, ໃຫ້ໄປຫາການຕັ້ງຄ່າ"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"ແບ່ງປັນ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string>
     <string name="action_split" msgid="2098009717623550676">"ແບ່ງ"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ແຕະແອັບອື່ນເພື່ອໃຊ້ໜ້າຈໍແຍກ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ຍົກເລີກ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ອອກຈາກາກນເລືອກການແບ່ງໜ້າຈໍ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ເລືອກແອັບອື່ນເພື່ອໃຊ້ການແບ່ງໜ້າຈໍ"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ຮັບການແນະນຳແອັບໂດຍອີງໃສ່ສິ່ງທີ່ເຮັດປະຈຳຂອງທ່ານ"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ກົດຕົວຂັ້ນຄ້າງໄວ້ເພື່ອປັກໝຸດແຖບໜ້າວຽກ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ເຮັດສິ່ງຕ່າງໆໄດ້ຫຼາຍຂຶ້ນດ້ວຍແຖບໜ້າວຽກ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ເພື່ອໃຫ້ແຖບໜ້າວຽກສະແດງຢູ່ລຸ່ມໜ້າຈໍຂອງທ່ານຢູ່ສະເໝີ, ໃຫ້ແຕະຕົວແບ່ງຄ້າງໄວ້"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ແຕະປຸ່ມຄຳສັ່ງຄ້າງໄວ້ເພື່ອຊອກຫາສິ່ງທີ່ຢູ່ເທິງໜ້າຈໍຂອງທ່ານ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ສິນຄ້ານີ້ໃຊ້ສ່ວນທີ່ເລືອກຂອງໜ້າຈໍຂອງທ່ານເພື່ອຊອກຫາ. ເປັນໄປຕາມ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ນະໂຍບາຍຄວາມເປັນສ່ວນຕົວ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ແລະ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ຂໍ້ກຳນົດບໍລິການ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ຂອງ Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ແລ້ວໆ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ໜ້າຫຼັກ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index c5839e3..47c3670 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Turite perbraukti nuo dešiniojo ar kairiojo krašto"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Turite perbraukti nuo dešiniojo ar kairiojo krašto link ekrano vidurio ir pakelti pirštą"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Išmokote, kaip sugrįžti perbraukiant iš dešinės. Toliau sužinosite, kaip perjungti programas."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Atlikote grįžimo atgal gestą. Toliau sužinosite, kaip perjungti programas."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Atlikote grįžimo atgal gestą"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nebraukite per arti ekrano apačios"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Norėd. pak. grįžimo gesto jautr., eikite į sk. „Nustatymai“"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Bendrinti"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string>
     <string name="action_split" msgid="2098009717623550676">"Išskaidymo režimas"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Išsaug. progr. porą"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Išskaidyto ekrano režimas palietus kitą programą"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Išskaidyto ekrano režimą naudokite kita programa"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atšaukti"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Išeiti iš išskaidyto ekrano pasirinkimo"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Išskaidyto ekrano režimą naudokite kita programa"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Gaukite programų pasiūlymų pagal savo veiklą"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Ilgai paspauskite daliklį, kad prisegtumėte užduočių juostą"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Atlikite daugiau naudodami Užduočių juostą"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visada rodyti užduočių juostą"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Jei norite, kad užduočių juosta visada būtų rodoma ekrano apačioje, palieskite ir palaikykite daliklį"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekrane rodomo turinio paieška palietus ir laikant veiksmų klavišą"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Šis produktas paieškai naudoja pasirinktą ekrano dalį. Taikomos „Google“ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>privatumo politikos<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ir <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>paslaugų teikimo sąlygos<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Uždaryti"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Atlikta"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Pagrindinis"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 063a626..276120b 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Notīrīt visu"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Jāvelk no pašas labās vai kreisās malas."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Jāvelk no ekrāna labās vai kreisās malas uz vidu un jāatlaiž."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Jūs esat apguvis, kā vilkt no labās malas, lai pārietu atpakaļ. Tagad mācieties pārslēgt lietotnes."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Jūs sekmīgi veicāt atgriešanās žestu. Tagad varat iemācīties, kā pārslēgt lietotnes."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Jūs sekmīgi veicāt atgriešanās žestu."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nevelciet pārāk tuvu ekrāna apakšdaļai."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Atgriešanās žesta jutīguma līmeni varat mainīt iestatījumos."</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Kopīgot"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
     <string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Saglabāt pāri"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atcelt"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Izejiet no ekrāna sadalīšanas režīma atlases."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Skatiet ieteiktās lietotnes, balstoties uz jūsu ieradumiem"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Nospiediet/turiet atdalītāju, lai piespraustu uzdevumu joslu"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Plašākas iespējas, izmantojot uzdevumu joslu"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vienmēr rādīt uzdevumu joslu"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Lai uzdevumu joslu rādītu apakšdaļā, pieskarieties atdalītājam un turiet"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Pieskarieties darbību taustiņam un turiet to, lai meklētu ekrānā redzamo saturu"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Šis produkts meklēšanai izmanto atlasīto ekrāna daļu. Ir spēkā Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>konfidencialitātes politika<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> un <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>pakalpojumu sniegšanas noteikumi<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gatavs"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Sākums"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 61d34dd..539448d 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Избриши ги сите"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Повлечете од крајниот десен или крајниот лев раб"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Повлечете од десниот или левиот раб кон средината на екранот и пуштете"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научивте како да повлекувате оддесно за враќање назад. Научете и како да се префрлате помеѓу апликациите."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Го научивте движењето за враќање назад. Научете го и движењето за префрлање помеѓу апликациите."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Завршивте со упатството за враќање назад"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не повлекувајте преблиску до дното на екранот"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"За да ја промените чувствителноста, одете во „Поставки“"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Сподели"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
     <string name="action_split" msgid="2098009717623550676">"Раздели"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Зачувај го паров"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Изберете друга апликација за да користите поделен екран"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излези од изборот на поделен екран"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескокни"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте го екранот"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Обука за лентата со задачи"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Повлечете апликација настрана за да користите 2 апликации"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Полека повлечете нагоре за да се прикаже лентата со задачи"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Повлечете апликација настрана за да користите 2 апликации одеднаш"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Полека повлечете нагоре за да се прикаже „Лентата со задачи“"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Добивајте предлози за апликации според вашата рутина"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Притиснете долго на разделникот за да ја закачите „Лентата со задачи“"</string>
-    <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повеќе со една лента со задачи"</string>
+    <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете сешто со „Лентата со задачи“"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Како секогаш да се прикажува „Лентата со задачи“"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Допрете и задржете го разделникот за да може „Лентата со задачи“ секогаш да се прикажува на дното на екранот"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Допрете и задржете го копчето за дејство за да пребарувате на екранот"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Производов го користи избраниот дел од екранот за пребарување. Важат <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Политиката за приватност<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Условите за користење<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> на Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Дома"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index f9e7827..90ceeff 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്‌ക്ടോപ്പ്"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്‌ക്കുക"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"വലത്തേയറ്റത്തെയോ ഇടത്തേയറ്റത്തെയോ അരികിൽ നിന്നാണ് സ്വെെപ്പ് ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കുക"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"വലതോ ഇടതോ അരികിൽ നിന്ന് സ്‌ക്രീനിന്റെ മധ്യഭാഗത്തേക്കാണ് സ്വെെപ്പ് ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കുക"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"മടങ്ങാൻ വലതുഭാഗത്ത് നിന്ന് സ്വൈപ്പ് ചെയ്യുന്ന രീതി മനസ്സിലായി. ഇനി, ആപ്പുകൾ മാറുന്ന രീതി അറിയുക."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി. അടുത്തത്, എങ്ങനെ ആപ്പുകൾ തമ്മിൽ മാറാമെന്ന് മനസ്സിലാക്കുക."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"സ്‌ക്രീനിന്റെ ഏറ്റവും അടിഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്യുന്നില്ലെന്ന് ഉറപ്പാക്കുക"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ബാക്ക്ജെസ്റ്ററിന്റെ സെൻസിറ്റിവിറ്റി മാറ്റാൻ ക്രമീകരണത്തിൽ പോകൂ"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"പങ്കിടുക"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
     <string name="action_split" msgid="2098009717623550676">"വിഭജിക്കുക"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ആപ്പ് ജോടി സംരക്ഷിക്കൂ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"സ്പ്ലിറ്റ് സ്ക്രീനിന് മറ്റൊരു ആപ്പിൽ ടാപ്പ് ചെയ്യൂ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"സ്ക്രീൻ വിഭജന മോഡ് ഉപയോഗിക്കാൻ മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"റദ്ദാക്കുക"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"സ്‌ക്രീൻ വിഭജന തിരഞ്ഞെടുപ്പിൽ നിന്ന് പുറത്തുകടക്കുക"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"സ്ക്രീൻ വിഭജന മോഡിന് മറ്റൊരു ആപ്പ് തിരഞ്ഞെടുക്കൂ"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"നിങ്ങളുടെ ദിനചര്യ അനുസരിച്ച് ആപ്പ് നിർദ്ദേശങ്ങൾ നേടുക"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ടാസ്‌ക്ബാർ പിൻ ചെയ്യാൻ ഡിവൈഡറിൽ ദീർഘനേരം അമർത്തുക"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ടാസ്‌ക്‌ബാർ ഉപയോഗിച്ച് കൂടുതൽ ചെയ്യുക"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"എല്ലായ്‌പ്പോഴും ടാസ്‌ക്‌ബാർ കാണിക്കുക"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ടാസ്‌ക്ബാർ എല്ലായ്‌പ്പോഴും നിങ്ങളുടെ സ്‌ക്രീനിന്റെ ചുവടെ കാണിക്കുന്നതിന് ഡിവൈഡറിൽ സ്‌പർശിച്ച് പിടിക്കുക"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"നിങ്ങളുടെ സ്‌ക്രീനിൽ എന്താണ് ഉള്ളതെന്ന് തിരയാൻ ആക്ഷൻ കീ സ്‌പർശിച്ച് പിടിക്കുക"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"തിരയുന്നതിന് ഈ ഉൽപ്പന്നം സ്‌ക്രീനിലെ തിരഞ്ഞെടുത്ത ഭാഗം ഉപയോഗിക്കുന്നു. Google-ന്റെ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>സ്വകാര്യതാ നയവും<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>സേവന നിബന്ധനകളും<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ബാധകമാണ്."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"പൂർത്തിയായി"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ഹോം"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 1b86948..c021d21 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Бүгдийг арилгах"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Та баруун зах эсвэл зүүн захын ирмэгээс шударна уу"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Та баруун эсвэл зүүн ирмэгээс дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Та буцах зангааг гүйцэтгэлээ. Дараа нь аппуудыг хэрхэн сэлгэх талаар мэдэж авна уу."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Та буцах зангааг гүйцэтгэлээ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
     <string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Апп хослуулалт хадгал"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Дэлгэц хуваахыг ашиглахын тулд өөр апп сонгоно уу"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Цуцлах"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Дэлгэцийг хуваах сонголтоос гарах"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Таны хэвшилд тулгуурлан санал болгож буй аппуудыг аваарай"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Ажлын хэсгийг бэхлэхийн тулд тусгаарлагчийг удаан дарна уу"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Ажлын хэсгийн тусламжтай илүү ихийг хийгээрэй"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Ажлын хэсгийг үргэлж харуулах"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Дэлгэцийнхээ доод талд Ажлын хэсгийг үргэлж харуулахын тулд хуваагч дээр хүрээд удаан дарна уу"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Дэлгэц дээрээ байгаа зүйлийг хайхын тулд тусгай товчлуурыг удаан дарна уу"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Энэ бүтээгдэхүүн хайхын тулд таны дэлгэцийн сонгосон хэсгийг ашигладаг. Google-н <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>нууцлалын бодлого<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> болон <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>үйлчилгээний нөхцөл<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> хэрэгжинэ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дууссан"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Гэр"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 722e17d..3fea03b 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अ‍ॅप वापर सेटिंग्ज"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"तुम्ही स्क्रीनच्या अगदी उजव्या किंवा अगदी डाव्या कडेपासून स्‍वाइप करत आहात खात्री करा"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"तुम्ही स्क्रीनच्या उजव्या किंवा डाव्या कडेपासून मध्यभागी स्‍वाइप करून सोडून देत आहात याची खात्री करा"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"मागे जाण्यासाठी उजवीकडून कसे स्‍वाइप करावे ते शिकलात. आता पुढे, ॲप्स कशी स्विच करायची ते जाणून घ्या."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तुम्ही गो बॅक जेश्चर पूर्ण केले. आता, ॲप्स कशी स्विच करायची ते जाणून घ्या."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तुम्ही गो बॅक जेश्चर पूर्ण केले आहे"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"तुम्ही स्क्रीनच्या तळाच्या अगदी जवळून स्‍वाइप करत नाही याची खात्री करा"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"बॅक जेश्चरची संवेदनशीलता बदलण्यासाठी, सेटिंग्ज वर जा"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"शेअर करा"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ॲपची जोडी सेव्ह करा"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द करा"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रीन निवडीतून बाहेर पडा"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"तुमच्या दिनक्रमावर आधारित ॲप सूचना मिळवा"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार पिन करण्यासाठी विभाजकावर प्रेस करून ठेवा"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार चा पुरेपूर वापर करा"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार नेहमी दाखवा"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"टास्कबार नेहमी तुमच्या स्क्रीनच्या तळाशी दाखवण्यासाठी, विभाजकाला स्पर्श करून धरून ठेवा"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"तुमच्या स्क्रीनवर काय आहे हे शोधण्यासाठी अ‍ॅक्शन की स्पर्श करून धरून ठेवा"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"शोधण्यासाठी हे उत्पादन तुमच्या स्क्रीनचा निवडलेला भाग वापरते. Google चे <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>गोपनीयता धोरण<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> आणि <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवा अटी<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू होतात."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करा"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"पूर्ण झाले"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 1959cd7..d998176 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pastikan anda meleret dari hujung sebelah kanan atau hujung sebelah kiri"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pastikan anda meleret dari tepi sebelah kanan atau kiri ke bahagian tengah skrin dan lepaskan"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Anda sudah belajar cara meleret dari kanan untuk kembali. Seterusnya, ketahui cara menukar apl."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Anda telah melengkapkan gerak isyarat undur. Seterusnya, ketahui cara menukar apl."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah melengkapkan gerak isyarat undur"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pastikan anda tidak meleret terlalu dekat dengan bahagian bawah skrin"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Utk mengubah kepekaan gerak isyarat undur, pergi ke Tetapan"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Kongsi"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
     <string name="action_split" msgid="2098009717623550676">"Pisah"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Simpan gandingan apl"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketik apl lain untuk menggunakan skrin pisah"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pilih apl lain untuk menggunakan skrin pisah"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Batal"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Keluar daripada pilihan skrin pisah"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih apl lain untuk menggunakan skrin pisah"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dapatkan cadangan apl berdasarkan rutin anda"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Tekan lama pada pembahagi untuk menyematkan Bar Tugas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Lakukan lebih banyak perkara dengan Bar Tugas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sentiasa paparkan Bar Tugas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Untuk sentiasa memaparkan Bar Tugas pada bahagian bawah skrin, sentuh &amp; tahan pembahagi"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Sentuh &amp; tahan kekunci tindakan untuk mencari kandungan yang dipaparkan pada skrin anda"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Produk ini menggunakan bahagian yang dipilih pada skrin untuk membuat carian. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Dasar Privasi<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dan <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Syarat Perkhidmatan<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google digunakan."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Laman Utama"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Bar Tugas dipaparkan"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Bar Tugas disembunyikan"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bar navigasi"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Sentiasa paparkan Bar Tugas"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Papar Bar Tugas selalu"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Tukar mod navigasi"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pembahagi Bar Tugas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 96ef54a..66c4e5f 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးရှင်းရန်"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်အစွန်း၏ ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ဖန်သားပြင်၏ ညာ (သို့) ဘယ်အစွန်းမှ အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"နောက်ပြန်သွားရန် ညာဘက်မှပွတ်ဆွဲနည်းကို သိသွားပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"နောက်သို့ လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ဖန်သားပြင် အောက်ခြေနှင့် အလွန်နီးကပ်စွာ ပွတ်ဆွဲခြင်းမရှိကြောင်း သေချာပါစေ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"နောက်ဆုတ်လက်ဟန်၏ အာရုံခံစွမ်းကိုပြောင်းရန် ‘ဆက်တင်များ’ သို့ သွားပါ"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
     <string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"မလုပ်တော့"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း ရွေးချယ်မှုမှ ထွက်ရန်"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"မျက်နှာပြင်ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ကျော်ရန်"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"ဖန်သားပြင်လှည့်ရန်"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"လုပ်ဆောင်စရာဘား ပညာပေး"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"အက်ပ် ၂ ခု တစ်ပြိုင်တည်းသုံးရန် အက်ပ်ကို ဘေးသို့ ဖိဆွဲပါ"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"အက်ပ် ၂ ခု တစ်ပြိုင်တည်းသုံးရန် အက်ပ်တစ်ခုကို ဘေးသို့ဖိဆွဲပါ"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Taskbar ပြရန် အပေါ်သို့ ဖြည်းဖြည်းပွတ်ဆွဲပါ"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ပုံမှန်အစီအစဉ်ပေါ် အခြေခံ၍ အက်ပ်အကြံပြုချက်များကို ရယူပါ"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Taskbar ပင်ထိုးရန် ခွဲခြားမျဉ်းကို ဖိနှိပ်ပါ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Taskbar ပင်ထိုးရန် ခွဲခြားမျဉ်းကို နှိပ်ထားပါ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Taskbar ဖြင့် ပိုမိုလုပ်ဆောင်နိုင်ခြင်း"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Taskbar ကို အမြဲပြပါ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Taskbar ကို စခရင်အောက်ခြေတွင် အမြဲပြရန် ခွဲခြားမျဉ်းကို တို့ထိ၍ ဖိထားပါ"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"သင့်စခရင်ပေါ်ရှိအရာကို ရှာရန် လုပ်ဆောင်ချက်ကီးကို ထိ၍ဖိထားပါ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ဤကုန်ပစ္စည်းသည် သင့်စခရင်၌ ရွေးထားသောအပိုင်းကိုသုံး၍ ရှာဖွေသည်။ Google ၏ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ကိုယ်ရေးအချက်အလက်လုံခြုံမှုဆိုင်ရာ မူဝါဒ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> နှင့် <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ဝန်ဆောင်မှုစည်းမျဉ်းများ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> အကျုံးဝင်သည်။"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ပြီးပြီ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ပင်မစာမျက်နှာ"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Taskbar ပြထားသည်"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Taskbar ဖျောက်ထားသည်"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"လမ်းညွှန်ဘား"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"‘လုပ်ဆောင်စရာဘား’ အမြဲပြပါ"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Taskbar အမြဲပြရန်"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"ရွှေ့ကြည့်သည့်မုဒ် ပြောင်းရန်"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"လုပ်ဆောင်စရာဘား ပိုင်းခြားစနစ်"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index f129361..6ee48dc 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Sørg for at du sveiper fra kanten helt til høyre eller venstre"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sørg for at du sveiper fra den høyre eller venstre kanten til midten av skjermen og slipper"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du har lært hvordan du sveiper fra høyre for å gå tilbake. I neste trinn lærer du å bytte app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har fullført bevegelsen for å gå tilbake. I neste trinn lærer du hvordan du bytter app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har fullført bevegelsen for å gå tilbake"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Sørg for at du ikke sveiper for nær bunnen av skjermen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Gå til Innstillinger for å endre tilbakebevegelsefølsomheten"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Del"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
     <string name="action_split" msgid="2098009717623550676">"Del opp"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avslutt valg av delt skjerm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Velg en annen app for å bruke delt skjerm"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag som er basert på rutinene dine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Trykk lenge på skillelinjen for å feste oppgavelinjen"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Gjør mer med oppgavelinjen"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vis alltid oppgavelinjen"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"For å alltid vise oppgavelinjen nederst på skjermen, trykk og hold på skillelinjen"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Trykk og hold på handlingstasten for å søke etter det som er på skjermen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dette produktet bruker den merkede delen av skjermen til å søke. Dette er underlagt Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>personvernregler<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> og <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>vilkår for bruk<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Lukk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Ferdig"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Hjem"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 7ff28f6..f6668c1 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटप"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
@@ -45,10 +46,11 @@
     <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सिफारिस गरिएका एपहरू देखाउने सुविधा असक्षम पारिएको छ"</string>
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"पूर्वानुमान गरिएको एप: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
-    <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"इसारामार्फत गरिने नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
+    <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"जेस्चर नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तपाईंले \'पछाडि जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तपाईंले \"पछाडि जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"स्क्रिनको फेदको धेरै नजिकसम्म स्वाइप नगर्नुहोस्"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'पछाडि\' नामक इसाराको संवेदनशीलता बदल्न सेटिङमा जानुहोस्"</string>
@@ -71,7 +73,7 @@
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"स्क्रिनबाट औँला उठाउनुअघि एपको विन्डोमा केही बेर छोइराख्नुहोस्"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"सीधै माथितिर स्वाइप गर्नुहोस् अनि रोकिनुहोस्"</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"तपाईंले इसाराहरू प्रयोग गर्ने तरिका सिक्नुभयो। इसारा अफ गर्न सेटिङमा जानुहोस्।"</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"तपाईंले जेस्चरहरू प्रयोग गर्ने तरिका सिक्नुभयो। इसारा अफ गर्न सेटिङमा जानुहोस्।"</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"तपाईंले \"एउटा एपबाट अर्को एपमा जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"एउटा एपबाट अर्को एपमा जान स्वाइप गर्नुहोस्"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"एउटा एपबाट अर्कोमा जान स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्, छोइराख्नुहोस् अनि औँला उठाउनुहोस्।"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"सेयर गर्नुहोस्"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"एपको पेयर सेभ गर्नुहोस्"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द गर्नुहोस्"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"स्प्लिट स्क्रिन मोडबाट बाहिरिनुहोस्"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"आफ्नो रुटिनका आधारमा एपसम्बन्धी सुझावहरू प्राप्त गर्नुहोस्"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार पिन गर्न डिभाइडरमा केही बेरसम्म थिच्नुहोस्"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार प्रयोग गरेर अझ धेरै कार्य गर्नुहोस्"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"टास्कबार सधैँ देखाउनुहोस्"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"आफ्नो स्क्रिनको पुछारमा टास्कबार सधैँ देखाइराख्न डिभाइडर टच एन्ड होल्ड गर्नुहोस्"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"आफ्नो स्क्रिनमा भएका कुराहरू खोज्न एक्सन कीमा टच एण्ड होल्ड गर्नुहोस्"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"यो उत्पादनले तपाईंले चयन गर्नुभएको स्क्रिनको भाग प्रयोग गरेर खोजी गर्छ। Google को <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>गोपनीयता नीति<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> र <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>सेवाका सर्तहरू<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> लागू हुन्छन्।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बन्द गर्नुहोस्"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"सम्पन्न भयो"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"होम"</string>
@@ -124,12 +132,12 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"टास्कबार देखाइएको छ"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"टास्कबार लुकाइएको छ"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"नेभिगेसन बार"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार सधैँ देखाइयोस्"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार सधैँ देखाउनुहोस्"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"नेभिगेसन मोड बदल्नुहोस्"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिभाइडर"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाइयोस्।}other{थप # वटा एप देखाइयोस्।}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"डेस्कटपमा एप हालिँदै छ"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"रद्द गर्नुहोस्"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index bf10bf2..c288868 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Alles wissen"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe vanaf de rechter- of linkerrand"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Je weet nu hoe je vanaf rechts kunt swipen om terug te gaan. Ontdek nu hoe je tussen apps schakelt."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Je weet nu hoe je het gebaar Terug maakt. Ontdek als volgende hoe je tussen apps schakelt."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Je weet nu hoe je het gebaar Terug maakt"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Swipe niet te dicht bij de onderkant van het scherm"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Open Instellingen om de gevoeligheid van Terug te wijzigen"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Delen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Splitsen"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"App-paar opslaan"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op nog een app om je scherm te splitsen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies een andere app om gesplitst scherm te gebruiken"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuleren"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sluit de selectie voor gesplitst scherm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Kies andere app om gesplitst scherm te gebruiken"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Krijg app-suggesties op basis van je routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Houd je vinger op de scheiding om de taakbalk vast te zetten"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Doe meer met de taakbalk"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"De taakbalk altijd tonen"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Houd de scheidingslijn ingedrukt als je de taakbalk altijd onderaan je scherm wilt tonen"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Houd je vinger op de actietoets om te zoeken naar wat er op je scherm staat"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Dit product gebruikt het geselecteerde gedeelte van je scherm om te zoeken. Het <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Privacybeleid<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> en de <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Servicevoorwaarden<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> van Google zijn van toepassing."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sluiten"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index d9f49e6..a7c5d44 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍‍"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ ବ୍ୟବହାର ସେଟିଂସ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ସବୁ ଖାଲି କରନ୍ତୁ"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ଆପଣ ସ୍କ୍ରିନର ତଳଭାଗର ଅତି ନିକଟରୁ ସ୍ୱାଇପ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ପଛକୁ ଫେରିବା ଜେଶ୍ଚରର ସମ୍ବେଦନଶୀଳତା ବଦଳାଇବାକୁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
     <string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ବାତିଲ କରନ୍ତୁ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ଚୟନରୁ ବାହାରି ଯାଆନ୍ତୁ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ଆପଣଙ୍କ ରୁଟିନ ଆଧାରରେ ଆପ ପରାମର୍ଶଗୁଡ଼ିକୁ ପାଆନ୍ତୁ"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ଟାସ୍କବାର ପିନ କରିବା ପାଇଁ ଡିଭାଇଡରକୁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ଟାସ୍କବାର ମାଧ୍ୟମରେ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ନିମ୍ନରେ ସର୍ବଦା ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଡିଭାଇଡରକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ କଣ ଅଛି ତାହା ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଆକ୍ସନ କୀ\'କୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ସର୍ଚ୍ଚ କରିବା ପାଇଁ ଏହି ପ୍ରଡକ୍ଟ ଆପଣଙ୍କ ସ୍କ୍ରିନର ଚୟନିତ ଅଂଶକୁ ବ୍ୟବହାର କରେ। Googleର <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ଗୋପନୀୟତା ନୀତି<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ଏବଂ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ସେବାର ସର୍ତ୍ତାବଳୀ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ଲାଗୁ ହୁଏ।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ହୋଇଗଲା"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ହୋମ"</string>
@@ -119,7 +128,7 @@
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ସ୍ୱିଚର"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"ବର୍ତ୍ତମାନର"</string>
     <string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
-    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କୁଇକ ସେଟିଂସ"</string>
     <string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string>
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ଟାସ୍କବାର ଦେଖାଯାଇଛି"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index cdf4d29..15be242 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -21,7 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"ਹਾਲੀਆ ਐਪਾਂ"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਪਾਸੇ ਦੇ ਬਿਲਕੁਲ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਦੇ ਹੋ"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਕ੍ਰੀਨ ਦੇ ਵਿਚਕਾਰ ਤੱਕ ਸਵਾਈਪ ਕਰਦੇ ਹੋ ਅਤੇ ਛੱਡ ਦਿੰਦੇ ਹੋ"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ਤੁਸੀਂ ਪਿੱਛੇ ਜਾਣ ਲਈ ਸੱਜੇ ਪਾਸੇ ਤੋਂ ਸਵਾਈਪ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣਿਆ। ਅੱਗੇ, ਐਪਾਂ ਵਿਚਾਲੇ ਸਵਿੱਚ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣੋ।"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਿਵੇਂ ਕਰਨੀ ਹੈ।"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਹਿੱਸੇ ਦੇ ਬਹੁਤ ਨੇੜੇ ਸਵਾਈਪ ਨਾ ਕਰੋ"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ਪਿੱਛੇ ਜਾਣ ਦੇ ਸੰਕੇਤ ਦੀ ਸੰਵੇਦਨਸ਼ੀਲਤਾ ਬਦਲਣ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
     <string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ਰੱਦ ਕਰੋ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਦੀ ਚੋਣ ਤੋਂ ਬਾਹਰ ਜਾਓ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ਛੱਡੋ"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"ਸਕ੍ਰੀਨ ਘੁਮਾਓ"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ਟਾਸਕਬਾਰ ਸਿੱਖਿਆ"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ਇੱਕੋ ਸਮੇਂ \'ਤੇ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ, ਐਪ ਨੂੰ ਪਾਸੇ ਵੱਲ ਘਸੀਟੋ"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਥੋੜ੍ਹਾ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ਇੱਕੋ ਵੇਲੇ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ, ਕਿਸੇ ਐਪ ਨੂੰ ਸਾਈਡ \'ਤੇ ਘਸੀਟੋ"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਹੌਲੀ ਜਿਹੀ ਉੱਤੇ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ਤੁਹਾਡੇ ਨਿਯਮਬੱਧ ਕੰਮ ਦੇ ਆਧਾਰ \'ਤੇ ਐਪ ਸੁਝਾਅ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ਟਾਸਕਬਾਰ \'ਤੇ ਪਿੰਨ ਕਰਨ ਲਈ ਵਿਭਾਜਕ \'ਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ਟਾਸਕਬਾਰ ਦਾ ਹੋਰ ਲਾਹਾ ਲਓ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣਾ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ਆਪਣੀ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਾਂ ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ, ਵਿਭਾਜਕ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਮੌਜੂਦ ਸਮੱਗਰੀ ਨੂੰ ਖੋਜਣ ਲਈ, ਕਾਰਵਾਈ ਕੁੰਜੀ ਨੂੰ ਸਪਰਸ਼ ਕਰ ਕੇ ਰੱਖੋ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ਇਹ ਉਤਪਾਦ ਖੋਜ ਕਰਨ ਲਈ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਦੇ ਚੁਣੇ ਹੋਏ ਹਿੱਸੇ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। Google ਦੀ <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>ਪਰਦੇਦਾਰੀ ਨੀਤੀ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ਅਤੇ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ਸੇਵਾ ਦੇ ਨਿਯਮ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ਲਾਗੂ ਹੁੰਦੇ ਹਨ।"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ਸਮਝ ਲਿਆ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ਘਰ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 7cc04ec..11f46bc 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Pulpit"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Wyczyść wszystko"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pamiętaj, aby przesuwać palcem od samej krawędzi (prawej lub lewej)"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pamiętaj, aby przesuwać palcem od prawej lub lewej krawędzi do środka ekranu i podnieść palec"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Wiesz już, jak przesuwać palcem, aby przejść wstecz. Poćwicz teraz przełączanie aplikacji."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Gest przejścia wstecz został opanowany. Poćwicz teraz przełączanie aplikacji."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Gest przejścia wstecz został opanowany"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pamiętaj, aby nie przesuwać palcem zbyt blisko dolnej części ekranu"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Czułość gestu cofania możesz zmienić w Ustawieniach"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
     <string name="action_split" msgid="2098009717623550676">"Podziel"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Zapisz parę"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Aby podzielić ekran, kliknij drugą aplikację"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Aby podzielić ekran, wybierz drugą aplikację"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anuluj"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Wyjdź z wyboru podzielonego ekranu"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Wybierz drugą aplikację, aby podzielić ekran"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pomiń"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Obróć ekran"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informacje o pasku aplikacji"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Przeciągnij aplikację w bok, aby używać 2 aplikacji naraz"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Aby wyświetlić pasek aplikacji, przesuń palcem krótko w górę"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Otrzymuj sugestie aplikacji na podstawie rutyny"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Przeciągnij aplikację na bok, aby używać 2 aplikacji naraz"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Aby wyświetlić pasek aplikacji, powoli przesuń palcem w górę"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Otrzymuj sugestie aplikacji na podstawie typowych działań"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Przytrzymaj separator, aby przypiąć pasek aplikacji"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Wykorzystaj potencjał paska aplikacji"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Zawsze wyświetlaj pasek aplikacji"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Aby zawsze wyświetlać pasek aplikacji u dołu ekranu, naciśnij i przytrzymaj linię dzielenia ekranu"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Aby rozpocząć wyszukiwanie na podstawie zawartości ekranu, naciśnij i przytrzymaj klawisz działania"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Usługa przy wyszukiwaniu używa zaznaczonego fragmentu ekranu. Obowiązują zapisy <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Polityki prywatności<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> i <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Warunków korzystania z usług<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zamknij"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotowe"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ekran główny"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index b90863d..5af1bf6 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
@@ -36,7 +37,7 @@
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Aceda facilmente às suas apps mais utilizadas, diretamente no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na última fila passam para o ecrã principal."</string>
     <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Aceda facilmente às suas apps mais utilizadas no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na fila dos favoritos passam para o ecrã principal."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Obter sugestões de apps"</string>
-    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não, obrigado"</string>
+    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não"</string>
     <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Definições"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"As apps mais utilizadas aparecem aqui e mudam em função das rotinas."</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Arraste as apps para fora da última fila para ver sugestões de apps."</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize rapidamente a partir da extremidade mais à direita ou mais à esquerda"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize rapidamente a partir da extremidade esquerda ou direita até ao centro do ecrã e solte"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendeu a deslizar a partir da direita para retroceder. A seguir, saiba como alternar entre apps."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Concluiu o gesto para retroceder. A seguir, saiba como alternar entre apps."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Concluiu o gesto para retroceder"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Garanta que não desliza rapidamente com o dedo demasiado perto da parte inferior do ecrã"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Altere a sensibilidade do gesto para voltar nas Definições."</string>
@@ -87,14 +89,16 @@
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
     <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
     <string name="allset_hint" msgid="459504134589971527">"Deslize rapidamente para cima para aceder ao ecrã principal"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão página inicial para aceder ao ecrã principal"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão do ecrã principal para aceder ao ecrã principal"</string>
     <string name="allset_description_generic" msgid="5385500062202019855">"Já pode começar a usar o seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Definições de navegação do sistema"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Partilhar"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar par de apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outra app para usar o ecrã dividido"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saia da seleção de ecrã dividido"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolher outra app para usar o ecrã dividido"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rodar ecrã"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Educação da Barra de tarefas"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arraste uma app para o lado para usar 2 apps em simultâneo"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Deslize lentamente para cima para mostrar a Barra de tarefas"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtenha sugestões de apps baseadas na sua rotina"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Deslize lentamente para cima para ver a Barra de tarefas"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Receba sugestões de apps baseadas na sua rotina"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantenha o divisor premido para fixar a Barra de tarefas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Faça mais com a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostre sempre a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar sempre a Barra de tarefas no fundo do ecrã, toque sem soltar no divisor"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Toque sem soltar na tecla de ação para pesquisar o que está no ecrã"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Este produto usa a parte selecionada do ecrã para pesquisar. Aplicam-se a <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e os <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termos de Utilização<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> da Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluir"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Barra de tarefas apresentada"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Barra de tarefas ocultada"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Barra de navegação"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Mostr. sempre Barra de tarefas"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre Barra de tarefas"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Alterar modo de navegação"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 2e4e2f8..9ea746c 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Remover tudo"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize da borda direita ou esquerda"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize da borda direita ou esquerda até o meio da tela e solte"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Você aprendeu a deslizar da direita para voltar. A seguir, aprenda a trocar de app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Você concluiu o gesto para voltar. A seguir, aprenda a trocar de app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Você concluiu o gesto para voltar"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Não deslize perto demais da parte inferior da tela"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Mude a sensibilidade do gesto de voltar nas configurações"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Compartilhar"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Salvar par de apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque em outro app para usar a tela dividida"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outro app para usar na tela dividida"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Sair da seleção de tela dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolha outro app para usar na tela dividida"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Receba sugestões de apps com base na sua rotina"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantenha o separador pressionado para fixar a Barra de tarefas"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Aproveite ainda mais a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Sempre mostrar a Barra de tarefas"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Toque e pressione o divisor para sempre mostrar a Barra de tarefas na parte de baixo da tela"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Toque e pressione a tecla de ação para pesquisar o que está na tela"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"O produto usa a parte selecionada da tela para pesquisar. O uso desses dados está sujeito à <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Política de Privacidade<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> e aos <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termos de Serviço<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> do Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluído"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Início"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 2f40dc4..e45e45a 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Șterge tot"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Glisează dinspre marginea dreaptă îndepărtată sau dinspre marginea stângă îndepărtată"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Glisează dinspre marginea dreaptă sau stângă spre mijlocul ecranului și eliberează"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ai învățat să revii la ecranul anterior glisând din dreapta. Acum învață să comuți între aplicații."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ați finalizat gestul „înapoi”. În continuare, aflați cum să comutați între aplicații."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ai finalizat gestul „înapoi”"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nu glisa prea aproape de partea de jos a ecranului"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Schimbă sensibilitatea gestului „Înapoi” accesând Setările"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Distribuie"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
     <string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Salvează perechea de aplicații"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Alege altă aplicație pentru a folosi ecranul împărțit"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulează"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ieși din selecția cu ecran împărțit"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Alege altă aplicație pentru ecranul împărțit"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Primește sugestii de aplicații în funcție de rutina ta"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Apasă lung pe separator pentru a fixa Bara de activități"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Fă mai multe din Bara de activități"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Afișează întotdeauna Bara de activități"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Pentru a afișa mereu Bara de activități în partea de jos a ecranului, atinge lung separatorul"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Atinge lung tasta de acțiuni ca să cauți pe ecran"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Acest produs folosește partea selectată a ecranului pentru a căuta. Se aplică <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Politica de confidențialitate<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> și <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Termenii și condițiile<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Închide"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gata"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ecran de pornire"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Bara de activități este afișată"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Bara de activități este ascunsă"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Bară de navigare"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Afișează întotdeauna bara de activități"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Afișează mereu bara"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Schimbă modul de navigare"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separator pentru bara de activități"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 0b7a193..5369d1e 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Включить режим для ПК"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Проведите справа налево или слева направо от самого края экрана."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Проведите от правого или левого края экрана к центру и отпустите палец."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Теперь вы знаете, как вернуться, проведя справа налево. Далее мы расскажем, как переключаться между приложениями."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Вы выполнили жест для перехода назад. Теперь мы расскажем, как переключаться между приложениями."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Вы выполнили жест для возврата на предыдущий экран."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Проведите пальцем не слишком близко к нижнему краю экрана."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Уровень чувствительности можно изменить в настройках."</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Разделить"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Сохранить приложения"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйдите из режима разделения экрана."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string>
@@ -109,8 +113,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Используйте два приложения сразу, перетащив одно в сторону."</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Чтобы открыть панель задач, медленно проведите снизу вверх."</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Получайте рекомендации, основанные на ваших действиях."</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Закрепите панель задач долгим нажатием на разделитель"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Закрепите панель задач долгим нажатием на разделитель."</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Используйте все возможности панели задач"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Закрепите панель задач внизу экрана"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Для этого нажмите на разделитель и удерживайте его."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Чтобы найти информацию об объекте на экране, нажмите и удерживайте клавишу действия"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Этот продукт использует выделенную часть экрана для поиска. При этом действуют <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Политика конфиденциальности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Условия использования<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Главный экран"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 0801a53..3b7598b 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ඩෙස්ක්ටොපය"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ඔබ ඈත දකුණු හෝ ඈත වම් දාරයේ සිට ස්වයිප් කරන බව සහතික කර ගන්න"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ඔබ දකුණු හෝ වම් දාරයේ සිට තිරයේ මැදට ස්වයිප් කර අත හරින බව සහතික කර ගන්න"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ආපසු යාමට දකුණේ සිට ස්වයිප් කරන්නේ කෙසේදැයි ඔබ දැන ගත්තේය. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කළා"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ඔබ තිරයේ පහළට ඉතාම සමීපව ස්වයිප් නොකරන බවට සහතික කර ගන්න"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ආපසු ඉංගිතයෙහි සංවේදීතාව වෙනස් කිරීමට, සැකසීම් වෙත යන්න"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
     <string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"යෙදුම් යුගල සුරකින්න"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"බෙදුම් තිරය භාවිත කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"අවලංගු කරන්න"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"බෙදීම් තිර තේරීමෙන් පිටවන්න"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"ඔබේ දිනචරියාව මත පදනම්ව යෙදුම් යෝජනා ලබා ගන්න"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"කාර්ය තීරුව ඇමිණීමට බෙදනය මත දිගු වේලාවක් ඔබන්න"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"කාර්ය තීරුව සමග තවත් කරන්න"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"සෑම විටම ඔබේ තිරයේ පතුලේ ඇති කාර්ය තීරුව පෙන්වීමට, බෙදුම්කරු ස්පර්ශ කර අල්ලාගෙන සිටින්න"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"ඔබේ තිරයෙහි ඇති දේ සෙවීමට ක්‍රියා යතුර ස්පර්ශ කර සිටින්න"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"මෙම නිෂ්පාදනය සෙවීමට ඔබේ තිරයෙහි තෝරන ලද කොටස භාවිතා කරයි. Google හි <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>පෞද්ගලිකත්ව ප්‍රතිපත්තිය<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> සහ <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>සේවා නියමයන්<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> අදාළ වේ."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"නිමයි"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"මුල් පිටුව"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 7e16184..c01f2f0 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Musíte potiahnuť z pravého alebo ľavého okraja do stredu obrazovky a potom uvoľniť"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste sa prejsť späť potiahnutím sprava. V ďalšom kroku sa naučíte prepínať aplikácie."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili ste gesto na prechod späť. V ďalšom kroku sa naučíte, ako prepínať aplikácie."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dokončili ste gesto na prechod späť"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nesmiete potiahnuť príliš blízko dolnej časti obrazovky"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Ak chcete zmeniť citlivosť gesta Späť, prejdite do Nastavení"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
     <string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Uložiť pár aplikácií"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdelíte klepnutím na inú aplikáciu"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Na použitie rozdelenej obrazovky vyberte ďalšiu aplikáciu"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušiť"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ukončite výber rozdelenej obrazovky"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Na použitie rozd. obrazovky vyberte inú aplikáciu"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Získavajte návrhy aplikácií na základe svojich zvykov"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dlhým stlačením rozdeľovača pripnete panel aplikácií"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Panel aplikácií vám ponúka ďalšie možnosti"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vždy zobrazovať panel aplikácií"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ak chcete, aby sa panel aplikácií vždy zobrazoval v dolnej časti obrazovky, pridržte rozdeľovač"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ak chcete vyhľadávať, čo je na obrazovke, pridržte akčný kláves."</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Táto služba používa na účely vyhľadávania vybranú časť obrazovky. Uplatňujú sa <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravidlá ochrany súkromia<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> a <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>zmluvné podmienky<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> spoločnosti Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Plocha"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 9df20c2..58e34f2 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Počisti vse"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite, da povlečete s skrajno desnega ali skrajno levega roba."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite, da povlečete z desnega ali levega roba do sredine zaslona in dvignete prst."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste se, kako povlečete z desne za vrnitev. Zdaj se naučite preklapljanja med aplikacijami."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvedli ste potezo za pomik nazaj. Zdaj se naučite preklapljanja med aplikacijami."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Izvedli ste potezo za pomik nazaj."</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite, da ne povlečete preblizu dna zaslona."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Občutljivost poteze za nazaj lahko spremenite v nastavitvah."</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Deli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
     <string name="action_split" msgid="2098009717623550676">"Razdeli"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Shrani par aplikacij"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Za razdeljeni zaslon se dotaknite še 1 aplikacije"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Prekliči"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Zapri izbiro razdeljenega zaslona"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izberite drugo aplikacijo za uporabo razdeljenega zaslona."</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Povlecite aplikacijo na stran za uporabo 2 aplikacij hkrati."</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Počasi povlecite navzgor za prikaz opravilne vrstice"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Prejemajte predloge aplikacij na podlagi svojih navad."</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Pridržite razdelilno črto, da pripnete opravilno vrstico"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Pridržite razdelilno črto, da pripnete opravilno vrstico."</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Naredite več z opravilno vrstico"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Stalni prikaz opravilne vrstice"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Če želite, da je opravilna vrstica vedno prikazana na dnu zaslona, pridržite razdelilno črto."</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Za iskanje po zaslonu se dotaknite in pridržite tipko za dejanja"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ta izdelek za iskanje uporablja izbrani del zaslona. Veljajo Googlov <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>pravilnik o zasebnosti<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> in <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>pogoji storitve<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zapri"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Končano"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Začetni zaslon"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Opravilna vrstica je prikazana"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Opravilna vrstica je skrita"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Vrstica za krmarjenje"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Stalen prikaz opravilne vrstice"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Stalen prikaz oprav. vrstice"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Spreminjanje načina navigacije"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelilnik opravilne vrstice"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 566a42d..7ae201f 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Pastroji të gjitha"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Sigurohu që të rrëshqasësh shpejt nga skaji më i djathtë ose më i majtë"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sigurohu që të rrëshqasësh shpejt nga skaji i djathtë ose i majtë drejt mesit të ekranit dhe lëshoje"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ke mësuar si të rrëshqasësh shpejt nga e djathta për t\'u kthyer prapa. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"E ke përfunduar gjestin e kthimit prapa. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"E ke përfunduar gjestin e kthimit prapa"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Sigurohu që të mos rrëshqasësh shpejt shumë afër pjesës së poshtme të ekranit"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Për të ndryshuar ndjeshmërinë e gjestit të kthimit prapa, shko te \"Cilësimet\""</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Ndaj"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string>
     <string name="action_split" msgid="2098009717623550676">"Ndaj"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Ruaj çiftin e aplikacioneve"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulo"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Dil nga zgjedhja e ekranit të ndarë"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Merr sugjerime për aplikacion bazuar në rutinën tënde"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Kryej një shtypje të gjatë te ndarësi për të gozhduar \"Shiritin e detyrave\""</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Bëj më shumë me \"Shiritin e detyrave\""</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Shfaq gjithmonë \"Shiritin e detyrave\""</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Prek e mbaj ndarësin dhe shfaq gjithmonë \"Shiritin e detyrave\" në fund të ekranit"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Prek dhe mbaj shtypur tastin e veprimit për të kërkuar për gjërat në ekran"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ky produkt përdor pjesën e zgjedhur të ekranit tënd për të kërkuar. Zbatohen <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Politika e privatësisë<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> dhe <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Kushtet e shërbimit<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> të Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Mbyll"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"U krye"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Faqja kryesore"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 78ce2ab..2a7239e 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Рачунар"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Обавезно превуците од саме десне или леве ивице"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Обавезно превуците од десне или леве ивице до средине екрана и отпустите"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Довршили сте покрет за повратак. Сада сазнајте како да промените апликације."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Довршили сте покрет за повратак"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Никако не превлачите превише близу дна екрана"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Осетљивост пок. за назад можете да промените у Подешавањима"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Дели"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Подели"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Сачувај пар апликација"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Одаберите другу апликацију да бисте користили подељени екран"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Излазак из бирања подељеног екрана"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Упутства на траци задатака"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Превуците на страну да бисте користили 2 апликације одједном"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Споро превуците нагоре да бисте приказали траку задатака"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Споро превуците нагоре да бисте видели траку задатака"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Добијајте предлоге апликација на основу рутине"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Дуго притискајте разделник да бисте закачили траку задатака"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Дуго притисните разделник да бисте закачили траку задатака"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Урадите више помоћу траке задатака"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Увек приказуј траку задатака"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Да би трака задатака увек била приказана у дну екрана, додирните и задржите разделник"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Додирните и задржите тастер радњи да бисте претражили оно што је на екрану"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Овај производ користи изабрани део екрана за претрагу. Примењују се Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>политика приватности<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> и <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>услови коришћења услуге<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Почетна"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index a1e2048..808cfe9 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Listan är tom"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Rensa alla"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Se till att du sveper ända från högerkanten eller vänsterkanten"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Se till att du sveper från den högra eller vänstra kanten till mitten av skärmen och sedan släpper"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Nu kan du svepa från höger för att gå tillbaka. Nu ska du få lära dig hur du byter mellan appar."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du är klar med rörelsen för att gå tillbaka. Nu ska du få lära dig hur du byter mellan appar."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du är klar med rörelsen för att gå tillbaka"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Se till att du inte sveper för nära skärmens nederkant"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Öppna inställningarna om du vill ändra rörelsens känslighet"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Dela"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
     <string name="action_split" msgid="2098009717623550676">"Delat"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Avsluta val av delad skärm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Välj en annan app för att använda delad skärm"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appförslag utifrån dina rutiner"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Tryck länge på avskiljaren om du vill fästa aktivitetsfältet"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Gör mer med aktivitetsfältet"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Visa alltid aktivitetsfältet"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Tryck länge på avgränsaren för att alltid visa aktivitetsfältet längst ned på skärmen"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Tryck länge på åtgärdstangenten för att söka efter det som finns på skärmen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Den här produkten använder den valda delen av skärmen för att söka. Googles <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>integritetspolicy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> och <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>användarvillkor<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> gäller."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klar"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Startsida"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 089672c..ba960ec 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto kabisa"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto hadi katikati ya skrini na uachilie"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Sasa jifunze jinsi ya kubadilisha programu."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Umekamilisha ishara ya kurudi nyuma. Hatua inayofuata, jifunze jinsi ya kubadilisha programu."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Umeweka ishara ya kurudi nyuma"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hakikisha hutelezeshi kidole karibu sana na sehemu ya chini ya skrini"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Kubadilisha hisi ya ishara ya nyuma, nenda kwenye Mipangilio"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Shiriki"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
     <string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Hifadhi jozi ya programu"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ghairi"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ondoka kwenye hali ya skrini iliyogawanywa"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Pata mapendekezo ya programu kulingana na ratiba yako"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Bonyeza kwa muda mrefu kigawaji ili ubandike Upauzana"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Kamilisha mengi kwa kutumia Upauzana huu"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Onyesha Upauzana kila wakati"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ili uonyeshe Upauzana kila wakati chini ya skrini yako, gusa na ushikilie kitenganishi"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Gusa na ushikilie kitufe cha vitendo ili utafute kilicho kwenye skrini yako"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bidhaa hii hutumia sehemu uliyochagua kwenye skrini yako kutafuta. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Sera ya Faragha<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> na <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Sheria na Masharti<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ya Google yatatumika."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Imemaliza"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Mwanzo"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Upauzana umeonyeshwa"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Upauzana umefichwa"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Sehemu ya viungo muhimu"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Onyesha Upauzana kila wakati"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Onyesha Zana kila wakati"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Badilisha hali ya usogezaji"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Kitenganishi cha Upauzana"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 49ddb8c..c5cbfcd 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"எல்லாம் அழி"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"வலது அல்லது இடது ஓரத்தின் விளிம்பிலிருந்து ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"வலது அல்லது இடது ஓரத்திலிருந்து திரையின் மையப் பகுதிக்கு ஸ்வைப் செய்தபிறகு விடுவிப்பதை உறுதிசெய்க"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"பின்செல்வதற்கு எப்படி வலதுபுறத்திலிருந்து ஸ்வைப் செய்வதென்று கற்றுக்கொண்டீர்கள். அடுத்து ஆப்ஸுக்கிடையே எப்படி மாறுவது என்பதை அறிக."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"பின்செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். அடுத்து, ஆப்ஸுக்கிடையே மாறுவது எப்படி என்பதை அறிக."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"பின்செல் சைகைப் பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"திரையின் கீழ்ப்பகுதிக்கு மிக நெருக்கமாக ஸ்வைப் செய்யவில்லை என்பதை உறுதிசெய்துகொள்ளுங்கள்"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"பின்செல் சைகையின் உணர்திறனை மாற்ற அமைப்புகளுக்குச் செல்க"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
     <string name="action_split" msgid="2098009717623550676">"பிரி"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ரத்துசெய்"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"திரைப் பிரிப்பு தேர்வில் இருந்து வெளியேறும்"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string>
@@ -106,11 +111,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"தவிர்"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"திரையைச் சுழற்றும்"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"செயல் பட்டியைப் பயன்படுத்தும் விதம்"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ஒரே நேரத்தில் 2 ஆப்ஸைப் பயன்படுத்தப் பக்கவாட்டில் இழுக்கவும்"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ஆப்ஸை பக்கவாட்டில் இழுத்து ஒரே நேரத்தில் 2 ஆப்ஸைப் பயன்படுத்தலாம்"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"செயல் பட்டியைக் காட்ட மேல்நோக்கி மெதுவாக ஸ்வைப் செய்யவும்"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"உங்கள் வழக்கத்திற்கேற்ப ஆப்ஸ் பரிந்துரைகளைப் பெறலாம்"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"பிரிப்பானை நீண்ட நேரம் அழுத்தி, செயல் பட்டியைப் பின் செய்க"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"பிரிப்பானை நீண்ட நேரம் அழுத்தி, செயல் பட்டியைப் பின் செய்யலாம்"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"செயல் பட்டி மூலம் மேலும் பலவற்றைச் செய்யுங்கள்"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"செயல் பட்டியை எப்போதும் காட்டுதல்"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"திரையின் கீழ்ப்பகுதியில் செயல் பட்டியை எப்போதும் காட்டுவதற்கு, பிரிப்பானைத் தொட்டுப் பிடித்திருக்கவும்"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"உங்கள் திரையில் உள்ளவற்றைத் தேடுவதற்கு ஆக்ஷன் பட்டனைத் தொட்டுப் பிடியுங்கள்"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"தேடுவதற்கு உங்கள் திரையின் தேர்ந்தெடுக்கப்பட்ட பகுதியை இந்தத் தயாரிப்பு பயன்படுத்துகிறது. Googleளின் <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>தனியுரிமைக் கொள்கையும்<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>சேவை விதிமுறைகளும்<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> பொருந்தும்."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"முடிந்தது"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"முகப்பு"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index d13764e..f2c06b4 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -21,7 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయండి"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"డెస్క్‌టాప్"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి ఐటెమ్‌లు ఏవీ లేవు"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్‌లు"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
     <string name="accessibility_recent_apps" msgid="4058661986695117371">"ఇటీవలి యాప్‌లు"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"కుడి వైపు చిట్ట చివరి లేదా ఎడమ వైపు చిట్ట చివరి అంచు నుండి స్వైప్ చేస్తున్నారని నిర్ధారించుకోండి"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"మీరు కుడి లేదా ఎడమ అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేశారని నిర్ధారించుకుని, మీ వేలిని ఎత్తండి"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"వెనుకకు వెళ్లడానికి కుడి నుండి స్వైప్ ఎలానో మీకు తెలుసు. తర్వాత, యాప్‌ల మధ్య ఎలా మారాలో తెలుసుకోండి."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"మీరు తిరిగి వెనక్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, యాప్‌ల మధ్య ఎలా మారాలో తెలుసుకోండి."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"మీరు పేజీ నుండి వెనుకకు వెళ్లే సంజ్ఞను పూర్తి చేశారు"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"మీరు స్క్రీన్ దిగువకు చాలా దగ్గరగా స్వైప్ చేయకుండా చూసుకోండి"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"వెనుక సంజ్ఞ సున్నితత్వం మార్చడానికి, సెట్టింగ్‌లకు వెళ్లండి"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"షేర్ చేయండి"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్‌షాట్"</string>
     <string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"యాప్ పెయిర్‌ను సేవ్ చేయండి"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌ను ట్యాప్ చేయండి"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"స్ప్లిట్ స్క్రీన్‌ను ఉపయోగించడానికి మరొక యాప్ ఎంచుకోండి"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"రద్దు చేయండి"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"స్ప్లిట్ స్క్రీన్ ఎంపిక నుండి ఎగ్జిట్ అవ్వండి"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"స్ప్లిట్ స్క్రీన్ ఉపయోగానికి మరొక యాప్ ఎంచుకోండి"</string>
@@ -109,8 +113,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"ఒకేసారి 2 యాప్‌లను ఉపయోగించడానికి యాప్‌ను పక్కకు లాగండి"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"టాస్క్‌బార్‌ను చూపడానికి నెమ్మదిగా పైకి స్వైప్ చేయండి"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"మీ రొటీన్ ఆధారంగా యాప్ సూచనలను పొందండి"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"టాస్క్‌బార్‌ను పిన్ చేయడానికి డివైడర్‌పై ఎక్కువసేపు నొక్కి, ఉంచడం"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"టాస్క్‌బార్‌ను పిన్ చేయడానికి డివైడర్‌ను ఎక్కువసేపు నొక్కండి"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"టాస్క్‌బార్‌తో మరిన్ని చేయండి"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"టాస్క్‌బార్‌ను నిరంతరం చూపండి"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"మీ స్క్రీన్ దిగువున టాస్క్‌బార్‌ను నిరంతరం చూపడానికి, డివైడర్‌ను తాకి, నొక్కి ఉంచండి"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"మీ స్క్రీన్‌లో ఏం ఉందో సెర్చ్ చేయడానికి యాక్షన్ కీని తాకి ఉంచండి"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ఈ ప్రోడక్ట్, సెర్చ్ చేయడానికి మీ స్క్రీన్‌లో ఎంచుకున్న భాగాన్ని ఉపయోగిస్తుంది. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>గోప్యతా పాలసీ<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>, <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>సర్వీస్ నియమాలు<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> వర్తిస్తాయి."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"మూసివేయండి"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"పూర్తయింది"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"మొదటి ట్యాబ్"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"టాస్క్‌బార్ చూపబడింది"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"టాస్క్‌బార్ దాచబడింది"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"నావిగేషన్ బార్"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"ఎప్పుడూ టాస్క్‌బార్ చూపించండి"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"టాస్క్‌బార్‌ను నిరంతరం చూపండి"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"నావిగేషన్ మోడ్‌ను మార్చండి"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"టాస్క్‌బార్ డివైడర్"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 7447b6d..c5f0b3e 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"เดสก์ท็อป"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ตรวจสอบว่าปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ไม่ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"เปลี่ยนความไวของท่าทางสัมผัสเพื่อย้อนกลับได้ที่การตั้งค่า"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"แชร์"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
     <string name="action_split" msgid="2098009717623550676">"แยก"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"บันทึกคู่แอป"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"แตะแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ยกเลิก"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ออกจากการเลือกโหมดแยกหน้าจอ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"เลือกแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"รับคำแนะนำเกี่ยวกับแอปตามกิจวัตรของคุณ"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"กดตัวแบ่งค้างไว้เพื่อปักหมุดแถบงาน"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ทำสิ่งต่างๆ ได้มากขึ้นด้วยแถบงาน"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"แสดงแถบงานเสมอ"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"หากต้องการให้แถบงานแสดงที่ด้านล่างหน้าจออยู่เสมอ ให้แตะตัวแบ่งค้างไว้"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"แตะปุ่มดำเนินการค้างไว้เพื่อค้นหาสิ่งที่อยู่บนหน้าจอ"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"ผลิตภัณฑ์นี้ใช้ส่วนที่เลือกของหน้าจอเพื่อค้นหา เป็นไปตาม<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>นโยบายความเป็นส่วนตัว<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>และ<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>ข้อกําหนดในการให้บริการ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>ของ Google"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"เสร็จ"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"หน้าแรก"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index cd432cc..5fbc57b 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"I-clear lahat"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Tiyaking magsa-swipe ka mula sa dulong kanan o dulong kaliwang gilid"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Tiyaking magsa-swipe mula sa kanan o kaliwang gilid papunta sa gitna ng screen at iangat ang daliri"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Natuto kang mag-swipe mula sa kanan para bumalik. Sunod, alamin kung paano magpalipat-lipat ng app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Nakumpleto mo na ang galaw para bumalik. Susunod, alamin kung paano magpalipat-lipat sa mga app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Nakumpleto mo na ang galaw para bumalik"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Tiyaking hindi ka magsa-swipe nang masyadong malapit sa ibaba ng screen"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Pumunta sa Settings para baguhin ang sensitivity ng pagbalik"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Ibahagi"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"I-save ang app pair"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pumili ng ibang app para gamitin ang split screen"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselahin"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Lumabas sa pagpili ng split screen"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pumili ng ibang app para gamitin ang split screen"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Makakuha ng mga iminumungkahing app batay sa iyong routine"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Pumindot nang matagal sa divider para i-pin ang Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Mas maraming magawa gamit ang Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Palaging ipakita ang Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para palaging ipakita ang Taskbar sa ibaba ng iyong screen, pindutin nang matagal ang divider"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Pindutin nang matagal ang action key para hanapin kung ano ang nasa iyong screen"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Ginagamit ng produktong ito ang piniling bahagi ng iyong screen para maghanap. Nalalapat ang <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Patakaran sa Privacy<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> at <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Mga Tuntunin ng Serbisyo<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> ng Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Isara"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tapos na"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Home"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Ipinapakita ang taskbar"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Nakatago ang taskbar"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigation bar"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Palaging ipakita ang Taskbar"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Ipakita lagi ang Taskbar"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Magpalit ng navigation mode"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divider ng Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index ed22286..79f8ad1 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Tümünü temizle"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"En sağ veya en sol kenardan kaydırdığınızdan emin olun"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ekranın sağ veya sol kenarından ortasına doğru sürükleyip bıraktığınızdan emin olun."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Geri dönmek için sağdan kaydırmayı öğrendiniz. Sırada uygulamalar arasında geçiş yapma var."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Geri dön hareketini tamamladınız. Sırada, uygulamalar arasında geçiş yapmayı öğrenmek var."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Geri dön hareketini tamamladınız"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ekranın alt kısmına çok yakın bir şekilde kaydırmadığınızdan emin olun"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Geri hareketinin hassasiyetini değiştirmek için Ayarlar\'a gidin"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Paylaş"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string>
     <string name="action_split" msgid="2098009717623550676">"Böl"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Uygulama çiftini kaydet"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"İptal"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Bölünmüş ekran seçiminden çıkın"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
@@ -107,10 +112,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı döndür"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Görev çubuğu eğitimi"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Aynı anda iki uygulama kullanmak için birini yana sürükleyin"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Görev çubuğunu göstermek için yukarı doğru yavaşça kaydırın"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Görev çubuğunun görünmesi için yukarı doğru yavaşça kaydırın"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Rutininize göre uygulama önerileri alın"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Görev çubuğunu sabitlemek için ayırıcıya uzun basın"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Görev çubuğuyla daha fazla şey yapın"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Görev çubuğunu sabitleyin"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ayırıcıya dokunup basılı tuttuğunuzda görev çubuğu ekranın alt kısmına sabitlenir"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekranınızda bulunan içerikleri aramak için eylem tuşuna dokunup basılı tutun"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu ürün, ekranınızın seçilen bölümünü kullanarak arama yapar. Google\'ın <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Gizlilik Politikası<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ve <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Hizmet Şartları<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> geçerlidir."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Kapat"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Bitti"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ana ekran"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 42fc6dd..c1ef51d 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Очистити все"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Проведіть пальцем від самого краю екрана (правого або лівого)"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Проведіть пальцем від правого або лівого краю до середини екрана й підніміть палець"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Тепер ви знаєте, як повернутися на попередній екран, провівши пальцем справа наліво. Дізнайтеся, як переключатися між додатками."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ви виконали жест \"Назад\". Тепер дізнайтеся, як переходити між додатками."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ви виконали жест \"Назад\""</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не проводьте пальцем надто близько до нижнього краю екрана"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Щоб змінити чутливість жесту \"Назад\", відкрийте налаштування"</string>
@@ -94,10 +97,12 @@
     <string name="action_share" msgid="2648470652637092375">"Поділитися"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Розділити"</string>
-    <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Зберегти пару"</string>
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток."</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасувати"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Вийти з режиму розділення екрана"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток"</string>
+    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
     <string name="split_widgets_not_supported" msgid="1355743038053053866">"Віджети наразі не підтримуються. Виберіть інший додаток."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string>
@@ -111,6 +116,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Отримуйте рекомендації додатків залежно від їх використання"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Утримуйте розділювач, щоб закріпити панель завдань"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Більше можливостей завдяки панелі завдань"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Завжди показувати панель завдань"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Щоб завжди показувати панель завдань унизу екрана, натисніть і втримуйте роздільник"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Для пошуку інформації, що відображається на екрані, натисніть і втримуйте клавішу дії"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Цей продукт використовує для пошуку вибрану частину екрана. Застосовуються <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Політика конфіденційності<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> та <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Загальні положення й умови<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Головний екран"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 0e5b602..69b4ba1 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے دور سے سوائپ کریں"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے اسکرین کے وسط تک سوائپ کریں اور پھر اپنی انگلی اٹھا لیں"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"آپ نے واپس جانے کے لیے دائیں کنارے سے سوائپ کرنے کا طریقہ سیکھ لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"آپ نے واپس جائیں اشارے کو مکمل کر لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"آپ نے واپس جائیں اشارے کو مکمل کر لیا"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے حصے سے زیادہ قریب سے سوائپ نہ کریں"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"پچھلے اشارے کی حساسیت تبدیل کرنے کے لیے ترتیبات پر جائیں"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
     <string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ایپس کے جوڑے کو محفوظ کریں"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"منسوخ کریں"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"اسپلٹ اسکرین کے انتخاب سے باہر نکلیں"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"اپنی روٹین پر مبنی ایپس کی تجاویز حاصل کریں"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ٹاسک بار کو پن کرنے کے لیے ڈیوائیڈر پر لانگ پریس کریں"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ٹاسک بار سے بہت کچھ کریں"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"ہمیشہ ٹاسک بار دکھائیں"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"ٹاسک بار کو ہمیشہ اپنی اسکرین کے نیچے دکھانے کے لیے، ڈیوائیڈر کو ٹچ کریں اور دبائے رکھیں"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"آپ کی اسکرین پر جو کچھ ہے اسے تلاش کرنے کے لیے ایکشن کلید کو ٹچ کریں اور دبائے رکھیں"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"‏یہ پروڈکٹ تلاش کرنے کے لیے آپ کی اسکرین کا منتخب حصہ استعمال کرتا ہے۔ Google کی <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>رازداری کی پالیسی<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> اور <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>سروس کی شرائط<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> لاگو ہوتی ہیں۔"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ہو گیا"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"ہوم"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 7cc157b..f548c19 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ekran chetidan boshlab oʻngdan yoki chapdan suring"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ekranning oʻng yoki chap chetidan oʻrtasigacha suring va qoʻyib yuboring"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ortga qaytish uchun oʻngdan surishni oʻrgandingiz. Endi ilovalarni almashtirishni oʻrganamiz."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ortga qaytish ishorasi darsini tamomladingiz. Endi ilovalarni almashtirishni oʻrganamiz."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ortga qaytish ishorasi darsini tamomladingiz"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Barmoqni ekran pastiga yaqin surmaslikka harakat qiling"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Orqaga ishorasi sezuvchanligi Sozlamalardan oʻzgartiriladi"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Ulashish"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skrinshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Ajratish"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Ilova juftini saqlash"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Bekor qilish"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Ekranni ikkiga ajratish tanlovidan chiqish"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Ekranni ikkiga ajratish uchun boshqa ilovani tanlang"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Harakatlaringiz asosida tavsiyalar oling."</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Vazifa panelini mahkamlash uchun ajratgichni bosib turing"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Vazifalar panelidan maksimal darajada foydalaning"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Vazifalar paneli doim chiqarilsin"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Vazifalar panelini ekranning pastki qismida doim chiqib turishi uchun ajratkichni bosib turing"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Ekrandagi element haqida maʼlumotni topish uchun amal tugmasini bosib turing"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Bu mahsulot qidirish uchun ekranning tanlangan qismidan foydalanadi. Google <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>maxfiylik siyosati<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> va <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>xizmat shartlari<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> tatbiq qilinadi."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tayyor"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Bosh ekran"</string>
@@ -124,7 +132,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Vazifalar paneli ochiq"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Vazifalar paneli yopiq"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Navigatsiya paneli"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Doim vazifalar paneli chiqsin"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Vazifalar paneli doim chiqarilsin"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Navigatsiya rejimini oʻzgartirish"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Vazifalar panelini ajratkich"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index bc9b348..136e1d2 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Xóa tất cả"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Hãy vuốt từ mép ngoài cùng bên phải hoặc ngoài cùng bên trái"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi nhấc ngón tay ra"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Bạn đã thực hiện xong cử chỉ quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Bạn đã thực hiện xong cử chỉ quay lại"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hãy nhớ không được vuốt quá gần phần dưới cùng của màn hình"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
     <string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Lưu cặp ứng dụng"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Huỷ"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Thoát khỏi lựa chọn chia đôi màn hình"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
@@ -109,8 +114,12 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Kéo một ứng dụng sang bên để dùng 2 ứng dụng cùng lúc"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Từ từ vuốt lên để Thanh tác vụ xuất hiện"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Nhận ứng dụng đề xuất dựa trên thói quen của bạn"</string>
-    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Nhấn và giữ trên đường phân chia để ghim Taskbar"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Nhấn và giữ trên đường phân chia để ghim Thanh tác vụ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Làm nhiều việc hơn qua Thanh tác vụ"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Luôn hiện Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Để luôn hiện Taskbar ở cuối màn hình, hãy nhấn và giữ đường phân chia"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Hãy chạm và giữ phím hành động để tìm xem trên màn hình của bạn có gì"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Sản phẩm này dùng phần được chọn trên màn hình để tìm kiếm. Có áp dụng <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Chính sách quyền riêng tư<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> và <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Điều khoản dịch vụ<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> của Google."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Xong"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Màn hình chính"</string>
@@ -124,7 +133,7 @@
     <string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"Đã hiện thanh thao tác"</string>
     <string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"Đã ẩn thanh thao tác"</string>
     <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Thanh điều hướng"</string>
-    <string name="always_show_taskbar" msgid="3608801276107751229">"Luôn hiển thị Taskbar"</string>
+    <string name="always_show_taskbar" msgid="3608801276107751229">"Luôn hiện Thanh tác vụ"</string>
     <string name="change_navigation_mode" msgid="9088393078736808968">"Thay đổi chế độ điều hướng"</string>
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Đường phân chia Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 2c740b7..b90d6bf 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -21,6 +21,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
+    <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
+    <skip />
     <string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -49,6 +51,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"确保从最右侧或最左侧边缘开始滑动"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"确保从右侧或左侧边缘滑动到屏幕中间位置后再松开手指"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"您已了解如何使用“从右侧向左滑动”手势返回。接下来学习切换应用吧!"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"您完成了“返回”手势教程。接下来了解如何切换应用。"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"您完成了“返回”手势"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"确保滑动时手的位置不要太靠近屏幕底部"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要调节“返回”手势的灵敏度,请转到“设置”"</string>
@@ -94,7 +97,9 @@
     <string name="action_share" msgid="2648470652637092375">"分享"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
     <string name="action_split" msgid="2098009717623550676">"拆分"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"保存应用组合"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"另外选择一个应用才可使用分屏模式"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分屏选择模式"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"另外选择一个应用才可使用分屏模式"</string>
@@ -106,15 +111,19 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"跳过"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋转屏幕"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"任务栏教程"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"将一个应用拖到一侧,即可一次使用两个应用"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"缓慢向上滑动即可显示任务栏"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根据您的日常安排获取应用建议"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"将一个应用拖到一侧,即可同时使用两个应用"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"缓慢上滑即可显示任务栏"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根据您的日常使用习惯获得应用建议"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"长按分隔线即可固定任务栏"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"体验任务栏的更多功能"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"始终显示任务栏"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"若要始终在屏幕底部显示任务栏,请轻触并按住分隔线"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"轻触并按住操作键,即可根据屏幕上的内容进行搜索"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"此产品会根据您在屏幕上选取的部分进行搜索。Google 的<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>《隐私权政策》<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>和<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>《服务条款》<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>在此适用。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"主屏幕"</string>
-    <string name="taskbar_button_a11y" msgid="5241161324875094465">"无障碍"</string>
+    <string name="taskbar_button_a11y" msgid="5241161324875094465">"无障碍功能"</string>
     <string name="taskbar_button_back" msgid="8558862226461164514">"返回"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME 切换器"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"最近用过"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index af7c663..45cf781 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -49,12 +50,13 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"請確保從螢幕最右側或最左側邊緣滑動"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"請確保從螢幕右側或左側邊緣往中央滑動,然後放開手指"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"你已瞭解如何透過「由右向左滑動」手勢返回。接下來一起瞭解如何切換應用程式。"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"你已完成「返回」手勢的教學課程。接下來一起瞭解如何切換應用程式。"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"你已完成「返回」手勢的教學課程"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"滑動時,手的位置不要太接近螢幕底部"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要變更「返回」手勢的敏感度,請前往「設定」"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"滑動即可返回"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"如要返回上一個畫面,請從螢幕左側或右側邊緣往中央滑動。"</string>
-    <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"如要返回上一個畫面,請用 2 隻手指從螢幕左側或右側邊緣往中央滑動。"</string>
+    <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"如要返回上一個畫面,請用兩指從螢幕左側或右側邊緣往中央滑動。"</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"返回"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"從螢幕左側或右側邊緣往中央滑動"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"請確保從螢幕底部邊緣向上滑動"</string>
@@ -64,7 +66,7 @@
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"你已完成「返回主畫面」手勢的教學課程"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"向上滑動即可返回主畫面"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"從螢幕底部向上滑動。這個手勢在所有畫面下都可讓你返回主畫面。"</string>
-    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"請用 2 隻手指從螢幕底部向上滑動。這個手勢在所有畫面下都可讓你返回主畫面。"</string>
+    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"請用兩指從螢幕底部向上滑動。這個手勢在所有畫面下都可讓你返回主畫面。"</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"返回主畫面"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"從螢幕底部向上滑動"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"太好了!"</string>
@@ -75,7 +77,7 @@
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"你已完成「切換應用程式」手勢的教學課程"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"滑動即可切換應用程式"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"如要切換應用程式,請從螢幕底部向上滑動並按住,然後放開。"</string>
-    <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"如要切換應用程式,請用 2 隻手指從螢幕底部向上滑動並按住,然後放開手指。"</string>
+    <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"如要切換應用程式,請用兩指從螢幕底部向上滑動並按住,然後放開手指。"</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"切換應用程式"</string>
     <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"從螢幕底部向上滑動並按住,然後放開"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"做得好!"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"分享"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式組合"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"輕按其他應用程式以使用分割螢幕"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇其他應用程式才能使用分割螢幕"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分割螢幕選取頁面"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"選擇其他應用程式才能使用分割螢幕"</string>
@@ -106,11 +110,15 @@
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string>
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"工作列教學"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"將應用程式拖曳到一邊,即可同時使用 2 個應用程式"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"慢慢向上滑動即可顯示工作列"</string>
-    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根據你的日常安排提供應用程式建議"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"將應用程式拖曳到一邊,同時使用兩個應用程式"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"慢慢向上掃即可顯示工作列"</string>
+    <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"獲取符合日常習慣的應用程式建議"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"長按分隔線即可固定工作列"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"工作列助你事半功倍"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要持續在畫面底部顯示工作列,請按住分隔線"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"此產品使用螢幕的特定部分進行搜尋。須受 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>私隱權政策<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>服務條款<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>》約束。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"住宅"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index e4ca3d9..ef811c4 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"請務必從螢幕最右側或最左側滑動"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"請務必從螢幕右側或左側往中央滑動,然後放開手指"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"你已瞭解如何透過「由右向左滑動」手勢返回。接著,一起來瞭解如何切換應用程式。"</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"你已完成「返回」手勢的教學課程。接著,一起來瞭解如何切換應用程式。"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"你已完成「返回」手勢的教學課程"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"滑動時,手的位置不要太接近螢幕底部"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要變更「返回」手勢的敏感度,請前往「設定」"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"分享"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式配對"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇要在分割畫面中使用的另一個應用程式"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"退出分割畫面選擇器"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"必須選擇另一個應用程式才能使用分割畫面"</string>
@@ -107,10 +111,14 @@
     <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"工作列教學課程"</string>
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"將應用程式拖曳到一邊即可同時使用 2 個應用程式"</string>
-    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"緩慢向上滑動即可讓工作列顯示在畫面上"</string>
+    <string name="taskbar_edu_stashing" msgid="5645461372669217294">"緩慢向上滑動讓工作列顯示在畫面上"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"根據你的日常安排建議應用程式"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"長按分隔線即可固定工作列"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"充分發揮工作列的功用"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"一律顯示工作列"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"如要一律在畫面底部顯示工作列,請按住分隔線"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"按住快捷操作鍵即可搜尋畫面上的內容"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"這項產品會搜尋你在畫面上選取的內容 (適用 Google 的《<xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>隱私權政策<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g>》和《<xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>服務條款<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g>》)。"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"主畫面"</string>
@@ -129,7 +137,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"新增應用程式至桌面"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 0526940..71c9227 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -21,6 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
     <string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
+    <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
     <string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
     <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
     <string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
@@ -49,6 +50,7 @@
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Qinisekisa ukuthi uswayipha ukusuka onqenqemeni olukude ngakwesokudla noma olukude ngakwesokunxele"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Qinisekisa ukuthi uswayipha ukusuka kunqenqema olungakwesokudla noma olungakwesokunxele ukuya maphakathi nesikrini bese uyadedela."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ufunde indlela yokuswayipha kusuka kwesokudla ukuze ubuyele emuva. Ngokulandelayo, funda indlela yokushintsha ama-app."</string>
+    <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ukuqedile ukuthinta kokubuyela emuva. Ngokulandelayo, funda indlela yokushintsha ama-app."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ukuqedile ukuthinta kokubuyela emuva"</string>
     <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Qinisekisa ukuba awuswayipheli eduze kakhulu naphansi kwesikrini"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Ukuze ushintshe ukuzwela kokuthinta emuva, iya Kumasethingi"</string>
@@ -94,7 +96,9 @@
     <string name="action_share" msgid="2648470652637092375">"Yabelana"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
     <string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Londoloza ukubhangqa i-app"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
+    <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Khansela"</b></string>
     <string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Phuma ekukhetheni ukuhlukaniswa kwesikrini"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
@@ -111,6 +115,10 @@
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Thola iziphakamiso ze-app ngokusekelwe kumjikelezo wakho"</string>
     <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Cindezela isikhathi eside kusihlukanisi ukuze uphine i-Taskbar"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Yenza okwengeziwe nge-Taskbar"</string>
+    <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Bonisa njalo i-Taskbar"</string>
+    <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Ukuze ubonise njalo i-Taskbar phansi kwesikrini sakho, thinta bese ubamba isihlukanisi"</string>
+    <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Thinta uphinde ubambe inkinobho yokufinyelela ukuze useshe lokho okukusikrini sakho"</string>
+    <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Lo mkhiqizo usebenzisa ingxenye ekhethiwe yesikrini sakho ukusesha. <xliff:g id="BEGIN_PRIVACY_LINK">&lt;a href="%1$s"&gt;</xliff:g>Inqubomgomo Yobumfihlo<xliff:g id="END_PRIVACY_LINK">&lt;/a&gt;</xliff:g> ye-Google kanye <xliff:g id="BEGIN_TOS_LINK">&lt;a href="%2$s"&gt;</xliff:g>Nemigomo Yesevisi<xliff:g id="END_TOS_LINK">&lt;/a&gt;</xliff:g> iyasebenza."</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kwenziwe"</string>
     <string name="taskbar_button_home" msgid="2151398979630664652">"Ikhaya"</string>
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index 7288774..ccc7f18 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -30,6 +30,11 @@
         <attr name="hoverBorderColor" format="color" />
     </declare-styleable>
 
+    <declare-styleable name="ClearAllButton">
+        <!-- focus border color for overview clear all button views -->
+        <attr name="focusBorderColor" />
+    </declare-styleable>
+
     <!--
          Gesture nav edu specific attributes. These attributes are used to customize Gesture nav edu
          view lottie animation colors in XML files.
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 8a3ffb5..28cdb99 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -26,6 +26,20 @@
     <string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
     <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
     <string name="widget_holder_factory_class" translatable="false">com.android.launcher3.uioverrides.QuickstepWidgetHolder$QuickstepHolderFactory</string>
+    <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
+    <string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
+    <string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
+    <string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
+    <string name="secondary_display_predictions_class" translatable="false">com.android.launcher3.secondarydisplay.SecondaryDisplayPredictionsImpl</string>
+    <string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
+    <string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
+    <string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
+    <string name="plugin_manager_wrapper_class" translatable="false">com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl</string>
+
+    <string name="nav_handle_long_press_handler_class" translatable="false"></string>
+    <string name="assist_utils_class" translatable="false"></string>
+    <string name="assist_state_manager_class" translatable="false"></string>
+    <string name="api_wrapper_class" translatable="false">com.android.launcher3.uioverrides.SystemApiWrapper</string>
 
     <!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
          determines how many thumbnails will be fetched in the background. -->
@@ -53,5 +67,5 @@
     <string name="setup_wizard_pkg" translatable="false" />
 
     <!-- This is a float because it is converted to dp later in DeviceProfile -->
-    <item name="taskbar_icon_size" type="dimen" format="float">48.4</item>
+    <item name="taskbar_icon_size" type="dimen" format="float">44</item>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 232c441..9ca8060 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -32,8 +32,11 @@
     <dimen name="overview_minimum_next_prev_size">50dp</dimen>
 
     <!--  Overview Task Views  -->
-    <!--  The primary task thumbnail uses up to this much of the total screen height/width  -->
+    <!--  The thumbnail uses up to this much of the total screen height/width in Overview -->
     <item name="overview_max_scale" format="float" type="dimen">0.7</item>
+    <!--  The thumbnail should not go smaller than this much of the total screen height/width in
+             tablet app to Overview carousel -->
+    <item name="overview_carousel_min_scale" format="float" type="dimen">0.46</item>
     <!--  A touch target for icons, sometimes slightly larger than the icons themselves  -->
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
     <!--  The icon size for the focused task, placed in center of touch target  -->
@@ -44,48 +47,38 @@
     <dimen name="overview_task_margin">16dp</dimen>
     <!--  The horizontal space between tasks  -->
     <dimen name="overview_page_spacing">16dp</dimen>
-    <!--  The min width of the thumbnail icon menu for non-split tasks  -->
-    <dimen name="task_thumbnail_icon_menu_min_width">156dp</dimen>
-    <!--  The max width of the thumbnail icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_max_width">216dp</dimen>
-    <!--  The width of the thumbnail icon menu background  -->
-    <dimen name="task_thumbnail_icon_menu_background_min_width">120dp</dimen>
-    <!--  The width of the icon menu text  -->
-    <dimen name="task_thumbnail_icon_menu_text_width">86dp</dimen>
-    <!--  The max width of the icon menu text  -->
-    <dimen name="task_thumbnail_icon_menu_text_max_width">118dp</dimen>
+    <!--  The collapsed max width of the icon menu text  -->
+    <dimen name="task_thumbnail_icon_menu_text_collapsed_max_width">86dp</dimen>
+    <!--  The expanded max width of the icon menu text  -->
+    <dimen name="task_thumbnail_icon_menu_text_expanded_max_width">118dp</dimen>
     <!--  The size of the icon menu text  -->
     <dimen name="task_thumbnail_icon_menu_text_size">14sp</dimen>
-    <!--  The max width of the thumbnail icon menu background  -->
-    <dimen name="task_thumbnail_icon_menu_background_max_width">164dp</dimen>
-    <!--  The height of the thumbnail icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_min_height">36dp</dimen>
-    <!--  The corner radius of the thumbnail icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_corner_radius">28dp</dimen>
-    <!--  The width of the thumbnail icon menu backgorund's corners when collapsed  -->
-    <dimen name="task_thumbnail_icon_menu_corner_width">36dp</dimen>
-    <!--  The max height of the thumbnail icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_max_height">52dp</dimen>
-    <!--  The size of the icon menu arrow  -->
-    <dimen name="task_thumbnail_icon_menu_arrow_size">24dp</dimen>
-    <!--  The size of the icon menu arrow drawable  -->
-    <dimen name="task_thumbnail_icon_menu_arrow_drawable_size">16dp</dimen>
-    <!--  The margin at the start of the task icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_start_margin">12dp</dimen>
-    <!--  The margin at the top of the task icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_top_margin">12dp</dimen>
+    <!--  The width of the thumbnail icon menu when collapsed (for non-split tasks)  -->
+    <dimen name="task_thumbnail_icon_menu_collapsed_width">156dp</dimen>
+    <!--  The width of the thumbnail icon menu when expanded -->
+    <dimen name="task_thumbnail_icon_menu_expanded_width">216dp</dimen>
+    <!--  The height of the thumbnail icon menu when collapsed  -->
+    <dimen name="task_thumbnail_icon_menu_collapsed_height">36dp</dimen>
+    <!--  The height of the thumbnail icon menu when expanded -->
+    <dimen name="task_thumbnail_icon_menu_expanded_height">52dp</dimen>
+    <!--  The margin at the top/start of the task icon menu when expanded  -->
+    <dimen name="task_thumbnail_icon_menu_expanded_top_start_margin">4dp</dimen>
+    <!--  The margin at the start of the background when collapsed  -->
+    <dimen name="task_thumbnail_icon_menu_background_margin_top_start">8dp</dimen>
+    <!--  The margin between the app name + app icon and app name + arrow icon when collapsed  -->
+    <dimen name="task_thumbnail_icon_menu_app_name_margin_horizontal_collapsed">8dp</dimen>
     <!--  The gap at the top of the task icon menu when expanded  -->
-    <dimen name="task_thumbnail_icon_menu_expanded_gap">6dp</dimen>
+    <dimen name="task_thumbnail_icon_menu_expanded_gap">2dp</dimen>
     <!--  The margin at the start of the task icon view in the icon menu  -->
     <dimen name="task_thumbnail_icon_view_start_margin">6dp</dimen>
     <!--  The space around the task icon arrow within the icon menu  -->
     <dimen name="task_thumbnail_icon_menu_arrow_margin">8dp</dimen>
-    <!--  The max space around the task icon within the icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_touch_max_margin">8dp</dimen>
-    <!--  The icon size for the icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_drawable_size">24dp</dimen>
-    <!--  The icon size for the icon menu  -->
-    <dimen name="task_thumbnail_icon_menu_drawable_max_size">32dp</dimen>
+    <!--  The size for the icon menu arrow -->
+    <dimen name="task_thumbnail_icon_menu_arrow_size">24dp</dimen>
+    <!--  The collapsed size for the icon menu icon -->
+    <dimen name="task_thumbnail_icon_menu_app_icon_collapsed_size">24dp</dimen>
+    <!--  The expanded icon size for the icon menu -->
+    <dimen name="task_thumbnail_icon_menu_app_icon_expanded_size">32dp</dimen>
     <!--  The size of the icon menu's icon touch target  -->
     <dimen name="task_thumbnail_icon_menu_drawable_touch_size">44dp</dimen>
     <dimen name="task_thumbnail_icon_menu_elevation">4dp</dimen>
@@ -105,6 +98,8 @@
     <dimen name="default_task_dismiss_drag_velocity_grid_focus_task">5dp</dimen>
 
     <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
+    <dimen name="recents_clear_all_outline_radius">24dp</dimen>
+    <dimen name="recents_clear_all_outline_padding">2dp</dimen>
 
     <!-- The speed in dp/s at which the user needs to be scrolling in recents such that we start
              loading full resolution screenshots. -->
@@ -322,7 +317,6 @@
 
     <!-- Taskbar -->
     <dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
-    <dimen name="taskbar_phone_size">@*android:dimen/navigation_bar_frame_height</dimen>
     <dimen name="taskbar_ime_size">48dp</dimen>
     <dimen name="taskbar_icon_min_touch_size">48dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
@@ -333,9 +327,9 @@
     <dimen name="taskbar_contextual_padding_top">8dp</dimen>
     <dimen name="taskbar_nav_buttons_size">44dp</dimen>
     <dimen name="taskbar_split_instructions_margin">48dp</dimen>
-    <dimen name="taskbar_contextual_button_margin">120dp</dimen>
+    <dimen name="taskbar_ime_switcher_button_margin_start">40dp</dimen>
     <dimen name="taskbar_suw_insets">48dp</dimen>
-    <dimen name="taskbar_suw_frame">48dp</dimen>
+    <dimen name="taskbar_suw_frame">96dp</dimen>
     <dimen name="taskbar_hotseat_nav_spacing">24dp</dimen>
     <dimen name="taskbar_contextual_buttons_size">35dp</dimen>
     <dimen name="taskbar_stashed_size">24dp</dimen>
@@ -354,6 +348,11 @@
     <dimen name="taskbar_icon_size_kids">32dp</dimen>
     <dimen name="taskbar_all_apps_button_translation_x_offset">6dp</dimen>
     <dimen name="taskbar_all_apps_search_button_translation_x_offset">6dp</dimen>
+    <dimen name="taskbar_contextual_button_suw_margin">64dp</dimen>
+    <dimen name="taskbar_contextual_button_suw_height">64dp</dimen>
+    <dimen name="taskbar_back_button_suw_start_margin">48dp</dimen>
+    <dimen name="taskbar_back_button_suw_bottom_margin">1dp</dimen>
+    <dimen name="taskbar_back_button_suw_height">72dp</dimen>
 
     <!-- Transient taskbar -->
     <dimen name="transient_taskbar_padding">12dp</dimen>
@@ -401,13 +400,18 @@
     <dimen name="taskbar_edu_features_lottie_width">170dp</dimen>
     <dimen name="taskbar_edu_features_lottie_height">106dp</dimen>
     <dimen name="taskbar_edu_features_horizontal_spacing">24dp</dimen>
+    <dimen name="taskbar_edu_features_tooltip_width_with_one_feature">412dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_two_features">428dp</dimen>
     <dimen name="taskbar_edu_features_tooltip_width_with_three_features">624dp</dimen>
+    <dimen name="taskbar_edu_circle_to_search_subtitle_text_size">12sp</dimen>
 
     <!--- Taskbar Pinning -->
     <dimen name="taskbar_pinning_popup_menu_width">300dp</dimen>
     <dimen name="taskbar_pinning_popup_menu_vertical_margin">16dp</dimen>
 
+    <!--- Floating Ime Inset height-->
+    <dimen name="floating_ime_inset_height">60dp</dimen>
+
     <!-- Recents overview -->
     <dimen name="recents_filter_icon_size">30dp</dimen>
 
@@ -416,15 +420,26 @@
     <dimen name="bubblebar_stashed_handle_width">55dp</dimen>
     <dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
     <dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
-    <dimen name="bubblebar_pointer_size">8dp</dimen>
+    <!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
+    background appropriately when close to the rounded corner -->
+    <dimen name="bubblebar_pointer_visible_size">9dp</dimen>
+    <dimen name="bubblebar_pointer_width">12dp</dimen>
+    <dimen name="bubblebar_pointer_height">10dp</dimen>
+    <dimen name="bubblebar_pointer_radius">2dp</dimen>
+    <!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
+    <dimen name="bubblebar_size_with_pointer">80dp</dimen>
     <dimen name="bubblebar_elevation">1dp</dimen>
+    <dimen name="bubblebar_drag_elevation">2dp</dimen>
     <dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
 
-    <dimen name="bubblebar_icon_size">50dp</dimen>
+    <dimen name="bubblebar_icon_size_small">32dp</dimen>
+    <dimen name="bubblebar_icon_size">36dp</dimen>
     <dimen name="bubblebar_badge_size">24dp</dimen>
     <dimen name="bubblebar_icon_overlap">12dp</dimen>
-    <dimen name="bubblebar_overflow_inset">24dp</dimen>
-    <dimen name="bubblebar_icon_spacing">3dp</dimen>
+    <dimen name="bubblebar_overflow_inset">16dp</dimen>
+    <dimen name="bubblebar_icon_spacing">6dp</dimen>
+    <dimen name="bubblebar_icon_spacing_large">8dp</dimen>
+    <dimen name="bubblebar_expanded_icon_spacing">12dp</dimen>
     <dimen name="bubblebar_icon_elevation">1dp</dimen>
 
     <!-- Bubble bar dismiss view -->
@@ -433,6 +448,11 @@
     <dimen name="bubblebar_dismiss_target_icon_size">24dp</dimen>
     <dimen name="bubblebar_dismiss_target_bottom_margin">50dp</dimen>
     <dimen name="bubblebar_dismiss_floating_gradient_height">548dp</dimen>
+    <dimen name="bubblebar_dismiss_zone_width">192dp</dimen>
+    <dimen name="bubblebar_dismiss_zone_height">242dp</dimen>
+
+    <!-- Bubble bar drop target -->
+    <dimen name="bubblebar_drop_target_corner_radius">36dp</dimen>
 
     <!-- Launcher splash screen -->
     <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
@@ -443,8 +463,7 @@
     <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
-    <dimen name="keyboard_quick_switch_taskview_icon_size">28dp</dimen>
-    <dimen name="keyboard_quick_switch_taskview_icon_margin">4dp</dimen>
+    <dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
     <dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
     <dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
     <dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
deleted file mode 100644
index 29779a7..0000000
--- a/quickstep/res/values/override.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Class overrides for launcher with quickstep. -->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
-
-  <string name="app_launch_tracker_class" translatable="false">com.android.launcher3.appprediction.PredictionAppTracker</string>
-
-  <string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
-
-  <string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
-
-  <string name="nav_handle_long_press_handler_class" translatable="false"></string>
-
-  <string name="assist_utils_class" translatable="false"></string>
-
-  <string name="secondary_display_predictions_class" translatable="false">com.android.launcher3.secondarydisplay.SecondaryDisplayPredictionsImpl</string>
-
-  <string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
-
-  <string name="assist_state_manager_class" translatable="false"></string>
-
-  <string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
-
-</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 6912e1a..fc3c0e3 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -26,6 +26,8 @@
     <string name="recent_task_option_pin">Pin</string>
     <!-- Title for an option to enter freeform mode for a given app -->
     <string name="recent_task_option_freeform">Freeform</string>
+    <!-- Title for an option to enter desktop windowing mode for a given app -->
+    <string name="recent_task_option_desktop">Desktop</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">No recent items</string>
@@ -105,6 +107,8 @@
     <string name="back_gesture_feedback_cancelled">Make sure you swipe from the right or left edge to the middle of the screen and let go</string>
     <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_complete_with_overview_follow_up">You learned how to swipe from the right to go back. Next up, learn how to switch apps.</string>
+    <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
+    <string name="back_gesture_feedback_complete_with_follow_up">You completed the go back gesture. Next up, learn how to switch apps.</string>
     <!-- Feedback shown after completing the back gesture step if the user started this tutorial individually. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_complete_without_follow_up">You completed the go back gesture</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
@@ -228,8 +232,11 @@
     <string name="action_screenshot">Screenshot</string>
     <!-- Label for a button that enters split screen selection mode. [CHAR_LIMIT=20] -->
     <string name="action_split">Split</string>
+    <!-- Label for a button that saves a new app pair. [CHAR_LIMIT=20] -->
+    <string name="action_save_app_pair">Save app pair</string>
     <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
     <string name="toast_split_select_app">Tap another app to use split screen</string>
+    <string name="toast_contextual_split_select_app">Choose another app to use split screen</string>
     <string name="toast_split_select_app_cancel"><b>Cancel</b></string>
     <string name="toast_split_select_cont_desc">Exit split screen selection</string>
     <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
@@ -264,6 +271,14 @@
     <string name="taskbar_edu_pinning">Long press on the divider to pin the Taskbar</string>
     <!-- Title in dialog that shows a user what they can do with the Taskbar. [CHAR_LIMIT=60] -->
     <string name="taskbar_edu_features">Do more with the Taskbar</string>
+    <!-- Title in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 60] -->
+    <string name="taskbar_edu_pinning_title">Always show the Taskbar</string>
+    <!-- Text in dialog that shows a user how to pin the Taskbar. [CHAR_LIMIT 150] -->
+    <string name="taskbar_edu_pinning_standalone">To always show the Taskbar on the bottom of your screen, touch &amp; hold the divider</string>
+    <!-- Title in dialog that shows a user how to invoke the Circle to Search feature. [CHAR_LIMIT 150] -->
+    <string name="taskbar_edu_circle_to_search_title">Touch &amp; hold the action key to search what\'s on your screen</string>
+    <!-- Message showed to user to disclose privacy information they need to accept in order to access the app. [CHAR LIMIT=200]-->
+    <string name="taskbar_edu_circle_to_search_disclosure">This product uses the selected part of your screen to search. Google\'s <xliff:g example="https://policies.google.com/privacy/embedded" id="begin_privacy_link">&lt;a href=\"%1$s\"&gt;</xliff:g>Privacy Policy<xliff:g id="end_privacy_link">&lt;/a&gt;</xliff:g> and <xliff:g example="https://policies.google.com/terms" id="begin_tos_link">&lt;a href=\"%2$s\"&gt;</xliff:g>Terms of Service<xliff:g id="end_tos_link">&lt;/a&gt;</xliff:g> apply.</string>
     <!-- Text on button to exit a tutorial [CHAR_LIMIT=16] -->
     <string name="taskbar_edu_close">Close</string>
     <!-- Text on button to finish a tutorial [CHAR_LIMIT=16] -->
@@ -309,6 +324,12 @@
             other{Show # more apps.}
         }</string>
 
+    <!-- Label for quick switch tile showing how many apps are available in desktop mode [CHAR LIMIT=NONE] -->
+    <string name="quick_switch_desktop">{count, plural,
+            =1{Show # desktop app.}
+            other{Show # desktop apps.}
+        }</string>
+
     <!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
     <string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
 
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index bdc86b2..16fb6d2 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -273,7 +273,7 @@
     </style>
 
     <style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
-        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceInverse</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
     </style>
 
     <style name="GestureTutorialActivity" parent="@style/AppTheme">
@@ -315,5 +315,6 @@
     <style name="WidgetPickerActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_light</item>
     </style>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/HomeTransitionController.java b/quickstep/src/com/android/launcher3/HomeTransitionController.java
deleted file mode 100644
index b264115..0000000
--- a/quickstep/src/com/android/launcher3/HomeTransitionController.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.transition.IHomeTransitionListener;
-
-/**
- * Controls launcher response to home activity visibility changing.
- */
-public class HomeTransitionController {
-
-    private final QuickstepLauncher mLauncher;
-    @Nullable private IHomeTransitionListener mHomeTransitionListener;
-
-    public HomeTransitionController(QuickstepLauncher launcher) {
-        mLauncher = launcher;
-    }
-
-    public void registerHomeTransitionListener() {
-        mHomeTransitionListener = new IHomeTransitionListener.Stub() {
-            @Override
-            public void onHomeVisibilityChanged(boolean isVisible) {
-                MAIN_EXECUTOR.execute(() -> {
-                    if (mLauncher.getTaskbarUIController() != null) {
-                        mLauncher.getTaskbarUIController().onLauncherVisibilityChanged(isVisible);
-                    }
-                });
-            }
-        };
-
-        SystemUiProxy.INSTANCE.get(mLauncher).setHomeTransitionListener(mHomeTransitionListener);
-    }
-
-    public void unregisterHomeTransitionListener() {
-        SystemUiProxy.INSTANCE.get(mLauncher).setHomeTransitionListener(null);
-        mHomeTransitionListener = null;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 5d4e19d..15180ef 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -24,9 +24,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
 import android.content.Context;
-import android.os.Build;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.view.IRemoteAnimationFinishedCallback;
@@ -37,7 +35,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.systemui.animation.RemoteAnimationDelegate;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 
 import java.lang.ref.WeakReference;
 
@@ -57,7 +55,6 @@
  * the runner implementation.  When this animation manager is destroyed, we remove the Launcher
  * reference to the runner, leaving only the weak ref from the runner.
  */
-@TargetApi(Build.VERSION_CODES.P)
 public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat {
 
     private static final RemoteAnimationFactory DEFAULT_FACTORY =
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index f64b5cf..523923d 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -15,14 +15,10 @@
  */
 package com.android.launcher3;
 
-import android.annotation.TargetApi;
-import android.os.Build;
-
 import com.android.quickstep.util.ActivityInitListener;
 
 import java.util.function.BiPredicate;
 
-@TargetApi(Build.VERSION_CODES.P)
 public class LauncherInitListener extends ActivityInitListener<Launcher> {
 
     /**
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 4898761..0697f47 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -43,6 +43,7 @@
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
 import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -64,8 +65,8 @@
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
-import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
-import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME_FALLBACK;
+import static com.android.quickstep.util.AnimUtils.clampToDuration;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
 
@@ -90,6 +91,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.Looper;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -117,6 +119,7 @@
 import androidx.annotation.Nullable;
 import androidx.core.graphics.ColorUtils;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.anim.AnimationSuccessListener;
@@ -155,14 +158,14 @@
 import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.FloatingWidgetView;
 import com.android.quickstep.views.RecentsView;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.DelegateLaunchAnimatorController;
+import com.android.systemui.animation.ActivityTransitionAnimator;
+import com.android.systemui.animation.DelegateTransitionAnimatorController;
 import com.android.systemui.animation.LaunchableView;
 import com.android.systemui.animation.RemoteAnimationDelegate;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.BlurUtils;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
 
 import java.io.PrintWriter;
@@ -170,6 +173,7 @@
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map.Entry;
 
 /**
  * Manages the opening and closing app transitions from Launcher
@@ -213,7 +217,8 @@
     public static final int TASKBAR_TO_APP_DURATION = 600;
     // TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
     // is solved.
-    public static final int TASKBAR_TO_HOME_DURATION = 300;
+    private static final int TASKBAR_TO_HOME_DURATION_FAST = 300;
+    private static final int TASKBAR_TO_HOME_DURATION_SLOW = 1000;
     protected static final int CONTENT_SCALE_DURATION = 350;
     protected static final int CONTENT_SCRIM_DURATION = 350;
 
@@ -351,6 +356,9 @@
                 new RemoteAnimationAdapter(runner, duration, statusBarTransitionDelay),
                 new RemoteTransition(runner.toRemoteTransition(),
                         mLauncher.getIApplicationThread(), "QuickstepLaunch"));
+        IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback);
+        options.setOnAnimationAbortListener(endCallback);
+        options.setOnAnimationFinishedListener(endCallback);
         return new ActivityOptionsWrapper(options, onEndCallback);
     }
 
@@ -743,34 +751,35 @@
         final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
-                    mOpeningXInterpolator);
-            FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
-                    mOpeningInterpolator);
+            FloatProp mDx = new FloatProp(0, prop.dX, mOpeningXInterpolator);
+            FloatProp mDy = new FloatProp(0, prop.dY, mOpeningInterpolator);
 
             FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
-                    prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
+                    prop.finalAppIconScale, mOpeningInterpolator);
             FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
-                    APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
+                    clampToDuration(LINEAR, APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION,
+                            APP_LAUNCH_DURATION));
 
-            FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
-                    APP_LAUNCH_DURATION, mOpeningInterpolator);
-            FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
-                    APP_LAUNCH_DURATION, mOpeningInterpolator);
+            FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
+                    mOpeningInterpolator);
+            FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius,
+                    mOpeningInterpolator);
 
             FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
-                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
+                    mOpeningInterpolator);
             FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
-                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
-            FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
-                    APP_LAUNCH_DURATION, mOpeningInterpolator);
-            FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
-                    APP_LAUNCH_DURATION, mOpeningInterpolator);
+                    mOpeningInterpolator);
+            FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd,
+                    mOpeningInterpolator);
+            FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd,
+                    mOpeningInterpolator);
 
-            FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
-                    NAV_FADE_OUT_INTERPOLATOR);
-            FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
-                    ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
+            FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
+                    NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION,
+                    APP_LAUNCH_DURATION));
+            FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
+                    NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN,
+                    ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION));
 
             @Override
             public void onUpdate(float percent, boolean initOnly) {
@@ -963,37 +972,36 @@
 
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
             float mAppWindowScale = 1;
-            final FloatProp mWidgetForegroundAlpha = new FloatProp(1 /* start */,
-                    0 /* end */, 0 /* delay */,
-                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
-            final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0 /* start */,
-                    1 /* end */, 0 /* delay */, 75 /* duration */, LINEAR);
-            final FloatProp mPreviewAlpha = new FloatProp(0 /* start */, 1 /* end */,
+            final FloatProp mWidgetForegroundAlpha = new FloatProp(1, 0, clampToDuration(
+                    LINEAR, 0, WIDGET_CROSSFADE_DURATION_MILLIS / 2, APP_LAUNCH_DURATION));
+
+            final FloatProp mWidgetFallbackBackgroundAlpha = new FloatProp(0, 1,
+                    clampToDuration(LINEAR, 0, 75, APP_LAUNCH_DURATION));
+            final FloatProp mPreviewAlpha = new FloatProp(0, 1, clampToDuration(
+                    LINEAR,
                     WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
-                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
+                    WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */,
+                    APP_LAUNCH_DURATION));
             final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
-                    0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator);
-            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION,
                     mOpeningInterpolator);
+            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, mOpeningInterpolator);
 
             // Window & widget background positioning bounds
             final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
-                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    mOpeningXInterpolator);
+                    windowTargetBounds.centerX(), mOpeningXInterpolator);
             final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
-                    windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    mOpeningInterpolator);
+                    windowTargetBounds.centerY(), mOpeningInterpolator);
             final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
-                    windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    mOpeningInterpolator);
+                    windowTargetBounds.width(), mOpeningInterpolator);
             final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
-                    windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    mOpeningInterpolator);
+                    windowTargetBounds.height(), mOpeningInterpolator);
 
-            final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
-                    NAV_FADE_OUT_INTERPOLATOR);
-            final FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
-                    ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
+            final FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
+                    NAV_FADE_OUT_INTERPOLATOR, 0, ANIMATION_NAV_FADE_OUT_DURATION,
+                    APP_LAUNCH_DURATION));
+            final FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
+                    NAV_FADE_IN_INTERPOLATOR, ANIMATION_DELAY_NAV_FADE_IN,
+                    ANIMATION_NAV_FADE_IN_DURATION, APP_LAUNCH_DURATION));
 
             @Override
             public void onUpdate(float percent, boolean initOnly) {
@@ -1088,7 +1096,12 @@
         }
 
         backgroundRadiusAnim.addListener(
-                AnimatorListeners.forEndCallback(depthController::dispose));
+                AnimatorListeners.forEndCallback(() -> {
+                    // reset the depth to match the main depth controller's depth
+                    depthController.stateDepth
+                            .setValue(mLauncher.getDepthController().stateDepth.getValue());
+                    depthController.dispose();
+                }));
 
         return backgroundRadiusAnim;
     }
@@ -1162,6 +1175,7 @@
         SystemUiProxy.INSTANCE.get(mLauncher)
                 .registerRemoteTransition(mLauncherOpenTransition, homeCheck);
         if (mBackAnimationController != null) {
+            mBackAnimationController.registerComponentCallbacks();
             mBackAnimationController.registerBackCallbacks(mHandler);
         }
     }
@@ -1169,6 +1183,7 @@
     public void onActivityDestroyed() {
         unregisterRemoteAnimations();
         unregisterRemoteTransitions();
+        mLauncher.removeOnDeviceProfileChangeListener(this);
         SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
         ORDERED_BG_EXECUTOR.execute(() -> mLauncher.getContentResolver()
                 .unregisterContentObserver(mAnimationRemovalObserver));
@@ -1201,6 +1216,7 @@
         mWallpaperOpenTransitionRunner = null;
         if (mBackAnimationController != null) {
             mBackAnimationController.unregisterBackCallbacks();
+            mBackAnimationController.unregisterComponentCallbacks();
             mBackAnimationController = null;
         }
     }
@@ -1291,7 +1307,7 @@
     /**
      * Returns view on launcher that corresponds to the closing app in the list of app targets
      */
-    private @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) {
+    public @Nullable View findLauncherView(RemoteAnimationTarget[] appTargets) {
         for (RemoteAnimationTarget appTarget : appTargets) {
             if (appTarget.mode == MODE_CLOSING) {
                 View launcherView = findLauncherView(appTarget);
@@ -1495,11 +1511,10 @@
         float startShadowRadius = areAllTargetsTranslucent(appTargets) ? 0 : mMaxShadowRadius;
         closingAnimator.setDuration(duration);
         closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
-            FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DECELERATE_1_7);
-            FloatProp mScale = new FloatProp(1f, 1f, 0, duration, DECELERATE_1_7);
-            FloatProp mAlpha = new FloatProp(1f, 0f, 25, 125, LINEAR);
-            FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, 0, duration,
-                    DECELERATE_1_7);
+            FloatProp mDy = new FloatProp(0, mClosingWindowTransY, DECELERATE_1_7);
+            FloatProp mScale = new FloatProp(1f, 1f, DECELERATE_1_7);
+            FloatProp mAlpha = new FloatProp(1f, 0f, clampToDuration(LINEAR, 25, 125, duration));
+            FloatProp mShadowRadius = new FloatProp(startShadowRadius, 0, DECELERATE_1_7);
 
             @Override
             public void onUpdate(float percent, boolean initOnly) {
@@ -1608,7 +1623,7 @@
                 || mLauncher.getWorkspace().isOverlayShown()
                 || shouldPlayFallbackClosingAnimation(appTargets);
 
-        boolean playWorkspaceReveal = true;
+        boolean playWorkspaceReveal = !fromPredictiveBack;
         boolean skipAllAppsScale = false;
         if (fromUnlock) {
             anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
@@ -1650,23 +1665,30 @@
         // targets list because it is already visible). In that case, we force
         // invisibility on touch down, and only reset it after the animation to home
         // is initialized.
-        if (launcherIsForceInvisibleOrOpening) {
+        if (launcherIsForceInvisibleOrOpening || fromPredictiveBack) {
             addCujInstrumentation(anim, playFallBackAnimation
-                    ? CUJ_APP_CLOSE_TO_HOME_FALLBACK : CUJ_APP_CLOSE_TO_HOME);
+                    ? Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME_FALLBACK
+                    : Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
 
-            anim.addListener(new AnimatorListenerAdapter() {
+            AnimatorListenerAdapter endListener = new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     super.onAnimationEnd(animation);
                     AccessibilityManagerCompat.sendTestProtocolEventToTest(
                             mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
                 }
-            });
+            };
+
+            if (fromPredictiveBack && rectFSpringAnim != null) {
+                rectFSpringAnim.addAnimatorListener(endListener);
+            } else {
+                anim.addListener(endListener);
+            }
 
             // Only register the content animation for cancellation when state changes
             mLauncher.getStateManager().setCurrentAnimation(anim);
 
-            if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+            if (mLauncher.isInState(LauncherState.ALL_APPS) && !fromPredictiveBack) {
                 Pair<AnimatorSet, Runnable> contentAnimator =
                         getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
                                 skipAllAppsScale);
@@ -1677,16 +1699,22 @@
                         contentAnimator.second.run();
                     }
                 });
-            } else {
-                if (playWorkspaceReveal) {
+            } else if (playWorkspaceReveal) {
                     anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
-                }
             }
         }
 
         return new Pair(rectFSpringAnim, anim);
     }
 
+    public static int getTaskbarToHomeDuration() {
+        if (enableScalingRevealHomeAnimation()) {
+            return TASKBAR_TO_HOME_DURATION_SLOW;
+        } else {
+            return TASKBAR_TO_HOME_DURATION_FAST;
+        }
+    }
+
     /**
      * Remote animation runner for animation from the app to Launcher, including recents.
      */
@@ -1768,19 +1796,18 @@
             if (launchingFromWidget) {
                 composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets,
                         wallpaperTargets, nonAppTargets, launcherClosing);
-                addCujInstrumentation(
-                        anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_WIDGET);
+                addCujInstrumentation(anim, Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_WIDGET);
                 skipFirstFrame = true;
             } else if (launchingFromRecents) {
                 composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
                 addCujInstrumentation(
-                        anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS);
+                        anim, Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_RECENTS);
                 skipFirstFrame = true;
             } else {
                 composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
-                addCujInstrumentation(anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON);
+                addCujInstrumentation(anim, Cuj.CUJ_LAUNCHER_APP_LAUNCH_FROM_ICON);
                 skipFirstFrame = false;
             }
 
@@ -1819,8 +1846,8 @@
 
             // The CUJ is logged by the click handler, so we don't log it inside the animation
             // library.
-            ActivityLaunchAnimator.Controller controllerDelegate =
-                    ActivityLaunchAnimator.Controller.fromView(viewToUse, null /* cujType */);
+            ActivityTransitionAnimator.Controller controllerDelegate =
+                    ActivityTransitionAnimator.Controller.fromView(viewToUse, null /* cujType */);
 
             if (controllerDelegate == null) {
                 return null;
@@ -1828,15 +1855,15 @@
 
             // This wrapper allows us to override the default value, telling the controller that the
             // current window is below the animating window.
-            ActivityLaunchAnimator.Controller controller =
-                    new DelegateLaunchAnimatorController(controllerDelegate) {
+            ActivityTransitionAnimator.Controller controller =
+                    new DelegateTransitionAnimatorController(controllerDelegate) {
                         @Override
                         public boolean isBelowAnimatingWindow() {
                             return true;
                         }
                     };
 
-            ActivityLaunchAnimator.Callback callback = task -> {
+            ActivityTransitionAnimator.Callback callback = task -> {
                 final int backgroundColor =
                         startingWindowListener.mBackgroundColor == Color.TRANSPARENT
                                 ? launcher.getScrimView().getBackgroundColor()
@@ -1844,15 +1871,17 @@
                 return ColorUtils.setAlphaComponent(backgroundColor, 255);
             };
 
-            ActivityLaunchAnimator.Listener listener = new ActivityLaunchAnimator.Listener() {
-                @Override
-                public void onLaunchAnimationEnd() {
-                    onEndCallback.executeAllAndDestroy();
-                }
-            };
+            ActivityTransitionAnimator.Listener listener =
+                    new ActivityTransitionAnimator.Listener() {
+                        @Override
+                        public void onTransitionAnimationEnd() {
+                            onEndCallback.executeAllAndDestroy();
+                        }
+                    };
 
             return new ContainerAnimationRunner(
-                    new ActivityLaunchAnimator.AnimationDelegate(controller, callback, listener));
+                    new ActivityTransitionAnimator.AnimationDelegate(
+                            controller, callback, listener));
         }
 
         /**
@@ -2028,7 +2057,7 @@
         private final RemoteAnimationTarget[] mAppTargets;
         private final Matrix mMatrix = new Matrix();
         private final Point mTmpPos = new Point();
-        private final Rect mCurrentRect = new Rect();
+        private final RectF mCurrentRectF = new RectF();
         private final float mStartRadius;
         private final float mEndRadius;
         private final SurfaceTransactionApplier mSurfaceApplier;
@@ -2095,25 +2124,24 @@
                 }
 
                 if (target.mode == MODE_CLOSING) {
-                    transferRectToTargetCoordinate(target, currentRectF, false, currentRectF);
-                    currentRectF.round(mCurrentRect);
+                    transferRectToTargetCoordinate(target, currentRectF, false, mCurrentRectF);
 
                     // Scale the target window to match the currentRectF.
                     final float scale;
 
                     // We need to infer the crop (we crop the window to match the currentRectF).
                     if (mWindowStartBounds.height() > mWindowStartBounds.width()) {
-                        scale = Math.min(1f, currentRectF.width() / mWindowOriginalBounds.width());
+                        scale = Math.min(1f, mCurrentRectF.width() / mWindowOriginalBounds.width());
 
-                        int unscaledHeight = (int) (mCurrentRect.height() * (1f / scale));
+                        int unscaledHeight = (int) (mCurrentRectF.height() * (1f / scale));
                         int croppedHeight = mWindowStartBounds.height() - unscaledHeight;
                         mTmpRect.set(0, 0, mWindowOriginalBounds.width(),
                                 mWindowStartBounds.height() - croppedHeight);
                     } else {
-                        scale = Math.min(1f, currentRectF.height()
+                        scale = Math.min(1f, mCurrentRectF.height()
                                 / mWindowOriginalBounds.height());
 
-                        int unscaledWidth = (int) (mCurrentRect.width() * (1f / scale));
+                        int unscaledWidth = (int) (mCurrentRectF.width() * (1f / scale));
                         int croppedWidth = mWindowStartBounds.width() - unscaledWidth;
                         mTmpRect.set(0, 0, mWindowStartBounds.width() - croppedWidth,
                                 mWindowOriginalBounds.height());
@@ -2121,7 +2149,7 @@
 
                     // Match size and position of currentRect.
                     mMatrix.setScale(scale, scale);
-                    mMatrix.postTranslate(mCurrentRect.left, mCurrentRect.top);
+                    mMatrix.postTranslate(mCurrentRectF.left, mCurrentRectF.top);
 
                     builder.setMatrix(mMatrix)
                             .setWindowCrop(mTmpRect)
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 43716ab..23cb8e9 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -16,33 +16,90 @@
 
 package com.android.launcher3;
 
+import static android.content.ClipDescription.MIMETYPE_TEXT_INTENT;
 import static android.view.WindowInsets.Type.navigationBars;
 import static android.view.WindowInsets.Type.statusBars;
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
 import android.view.WindowInsetsController;
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.dragndrop.SimpleDragLayer;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.WidgetPredictionsRequester;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /** An Activity that can host Launcher's widget picker. */
 public class WidgetPickerActivity extends BaseActivity {
+    private static final String TAG = "WidgetPickerActivity";
+    /**
+     * Name of the extra that indicates that a widget being dragged.
+     *
+     * <p>When set to "true" in the result of startActivityForResult, the client that launched the
+     * picker knows that activity was closed due to pending drag.
+     */
+    private static final String EXTRA_IS_PENDING_WIDGET_DRAG = "is_pending_widget_drag";
+
+    // Intent extras that specify the desired widget width and height. If these are not specified in
+    // the intent, then widgets will not be filtered for size.
+    private static final String EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width";
+    private static final String EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height";
+    /**
+     * Widgets currently added by the user in the UI surface.
+     * <p>This allows widget picker to exclude existing widgets from suggestions.</p>
+     */
+    private static final String EXTRA_ADDED_APP_WIDGETS = "added_app_widgets";
+    /**
+     * A unique identifier of the surface hosting the widgets;
+     * <p>"widgets" is reserved for home screen surface.</p>
+     * <p>"widgets_hub" is reserved for glanceable hub surface.</p>
+     */
+    private static final String EXTRA_UI_SURFACE = "ui_surface";
+    private static final Pattern UI_SURFACE_PATTERN =
+            Pattern.compile("^(widgets|widgets_hub)$");
     private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
     private WidgetsModel mModel;
+    private LauncherAppState mApp;
+    private WidgetPredictionsRequester mWidgetPredictionsRequester;
     private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
 
+    private int mDesiredWidgetWidth;
+    private int mDesiredWidgetHeight;
+    private int mWidgetCategoryFilter;
+    @Nullable
+    private String mUiSurface;
+    // Widgets existing on the host surface.
+    @NonNull
+    private List<AppWidgetProviderInfo> mAddedWidgets = new ArrayList<>();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -50,9 +107,8 @@
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
 
-        LauncherAppState app = LauncherAppState.getInstance(this);
-        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
-
+        mApp = LauncherAppState.getInstance(this);
+        InvariantDeviceProfile idp = mApp.getInvariantDeviceProfile();
         mDeviceProfile = idp.getDeviceProfile(this);
         mModel = new WidgetsModel();
 
@@ -67,9 +123,33 @@
         widgetSheet.disableNavBarScrim(true);
         widgetSheet.addOnCloseListener(this::finish);
 
+        parseIntentExtras();
         refreshAndBindWidgets();
     }
 
+    private void parseIntentExtras() {
+        // A value of 0 for either size means that no filtering will occur in that dimension. If
+        // both values are 0, then no size filtering will occur.
+        mDesiredWidgetWidth =
+                getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_WIDTH, 0);
+        mDesiredWidgetHeight =
+                getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_HEIGHT, 0);
+
+        // Defaults to '0' to indicate that there isn't a category filter.
+        mWidgetCategoryFilter =
+                getIntent().getIntExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER, 0);
+
+        String uiSurfaceParam = getIntent().getStringExtra(EXTRA_UI_SURFACE);
+        if (uiSurfaceParam != null && UI_SURFACE_PATTERN.matcher(uiSurfaceParam).matches()) {
+            mUiSurface = uiSurfaceParam;
+        }
+        ArrayList<AppWidgetProviderInfo> addedWidgets = getIntent().getParcelableArrayListExtra(
+                EXTRA_ADDED_APP_WIDGETS, AppWidgetProviderInfo.class);
+        if (addedWidgets != null) {
+            mAddedWidgets = addedWidgets;
+        }
+    }
+
     @NonNull
     @Override
     public PopupDataProvider getPopupDataProvider() {
@@ -81,13 +161,210 @@
         return mDragLayer;
     }
 
+    @Override
+    public View.OnClickListener getItemOnClickListener() {
+        return v -> {
+            final AppWidgetProviderInfo info =
+                    (v instanceof WidgetCell) ? ((WidgetCell) v).getWidgetItem().widgetInfo : null;
+            if (info == null || info.provider == null) {
+                return;
+            }
+
+            setResult(RESULT_OK, new Intent()
+                    .putExtra(Intent.EXTRA_COMPONENT_NAME, info.provider)
+                    .putExtra(Intent.EXTRA_USER, info.getProfile()));
+
+            finish();
+        };
+    }
+
+    @Override
+    public View.OnLongClickListener getAllAppsItemLongClickListener() {
+        return view -> {
+            if (!(view instanceof WidgetCell widgetCell)) return false;
+
+            if (widgetCell.getWidgetView().getDrawable() == null
+                    && widgetCell.getAppWidgetHostViewPreview() == null) {
+                // The widget preview hasn't been loaded; so, we abort the drag.
+                return false;
+            }
+
+            final AppWidgetProviderInfo info = widgetCell.getWidgetItem().widgetInfo;
+            if (info == null || info.provider == null) {
+                return false;
+            }
+
+            ClipData clipData = new ClipData(
+                    new ClipDescription(
+                            /* label= */ "", // not displayed anywhere; so, set to empty.
+                            new String[]{MIMETYPE_TEXT_INTENT}
+                    ),
+                    new ClipData.Item(new Intent()
+                            .putExtra(Intent.EXTRA_USER, info.getProfile())
+                            .putExtra(Intent.EXTRA_COMPONENT_NAME, info.provider))
+            );
+
+            // Set result indicating activity was closed due a widget being dragged.
+            setResult(RESULT_OK, new Intent()
+                    .putExtra(EXTRA_IS_PENDING_WIDGET_DRAG, true));
+
+            // DRAG_FLAG_GLOBAL permits dragging data beyond app window.
+            return view.startDragAndDrop(
+                    clipData,
+                    new View.DragShadowBuilder(view),
+                    /* myLocalState= */ null,
+                    View.DRAG_FLAG_GLOBAL
+            );
+        };
+    }
+
+    /** Updates the model with widgets and provides them after applying the provided filter. */
     private void refreshAndBindWidgets() {
         MODEL_EXECUTOR.execute(() -> {
             LauncherAppState app = LauncherAppState.getInstance(this);
             mModel.update(app, null);
-            final ArrayList<WidgetsListBaseEntry> widgets =
-                    mModel.getWidgetsListForPicker(app.getContext());
-            MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
+            final List<WidgetsListBaseEntry> allWidgets =
+                    mModel.getFilteredWidgetsListForPicker(
+                            app.getContext(),
+                            /*widgetItemFilter=*/ widget -> {
+                                final WidgetAcceptabilityVerdict verdict =
+                                        isWidgetAcceptable(widget);
+                                verdict.maybeLogVerdict();
+                                return verdict.isAcceptable;
+                            }
+                    );
+            bindWidgets(allWidgets);
+            if (mUiSurface != null) {
+                Map<PackageUserKey, List<WidgetItem>> allWidgetsMap = allWidgets.stream()
+                        .filter(WidgetsListHeaderEntry.class::isInstance)
+                        .collect(Collectors.toMap(
+                                entry -> PackageUserKey.fromPackageItemInfo(entry.mPkgItem),
+                                entry -> entry.mWidgets)
+                        );
+                mWidgetPredictionsRequester = new WidgetPredictionsRequester(app.getContext(),
+                        mUiSurface, allWidgetsMap);
+                mWidgetPredictionsRequester.request(mAddedWidgets, this::bindRecommendedWidgets);
+            }
         });
     }
+
+    private void bindWidgets(List<WidgetsListBaseEntry> widgets) {
+        MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
+    }
+
+    private void bindRecommendedWidgets(List<ItemInfo> recommendedWidgets) {
+        MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mWidgetPredictionsRequester != null) {
+            mWidgetPredictionsRequester.clear();
+        }
+    }
+
+    private WidgetAcceptabilityVerdict isWidgetAcceptable(WidgetItem widget) {
+        final AppWidgetProviderInfo info = widget.widgetInfo;
+        if (info == null) {
+            return rejectWidget(widget, "shortcut");
+        }
+
+        if (mWidgetCategoryFilter > 0 && (info.widgetCategory & mWidgetCategoryFilter) == 0) {
+            return rejectWidget(
+                    widget,
+                    "doesn't match category filter [filter=%d, widget=%d]",
+                    mWidgetCategoryFilter,
+                    info.widgetCategory);
+        }
+
+        if (mDesiredWidgetWidth == 0 && mDesiredWidgetHeight == 0) {
+            // Accept the widget if the desired dimensions are unspecified.
+            return acceptWidget(widget);
+        }
+
+        final boolean isHorizontallyResizable =
+                (info.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0;
+        if (mDesiredWidgetWidth > 0 && isHorizontallyResizable) {
+            if (info.maxResizeWidth > 0
+                    && info.maxResizeWidth >= info.minWidth
+                    && info.maxResizeWidth < mDesiredWidgetWidth) {
+                return rejectWidget(
+                        widget,
+                        "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
+                        info.maxResizeWidth,
+                        mDesiredWidgetWidth);
+            }
+
+            final int minWidth = Math.min(info.minResizeWidth, info.minWidth);
+            if (minWidth > mDesiredWidgetWidth) {
+                return rejectWidget(
+                        widget,
+                        "min(minWidth[%d], minResizeWidth[%d]) > mDesiredWidgetWidth[%d]",
+                        info.minWidth,
+                        info.minResizeWidth,
+                        mDesiredWidgetWidth);
+            }
+        }
+
+        final boolean isVerticallyResizable =
+                (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0;
+        if (mDesiredWidgetHeight > 0 && isVerticallyResizable) {
+            if (info.maxResizeHeight > 0
+                    && info.maxResizeHeight >= info.minHeight
+                    && info.maxResizeHeight < mDesiredWidgetHeight) {
+                return rejectWidget(
+                        widget,
+                        "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
+                        info.maxResizeHeight,
+                        mDesiredWidgetHeight);
+            }
+
+            final int minHeight = Math.min(info.minResizeHeight, info.minHeight);
+            if (minHeight > mDesiredWidgetHeight) {
+                return rejectWidget(
+                        widget,
+                        "min(minHeight[%d], minResizeHeight[%d]) > mDesiredWidgetHeight[%d]",
+                        info.minHeight,
+                        info.minResizeHeight,
+                        mDesiredWidgetHeight);
+            }
+        }
+
+        if (!isHorizontallyResizable || !isVerticallyResizable) {
+            return rejectWidget(widget, "not resizeable");
+        }
+
+        return acceptWidget(widget);
+    }
+
+    private static WidgetAcceptabilityVerdict rejectWidget(
+            WidgetItem widget, String rejectionReason, Object... args) {
+        return new WidgetAcceptabilityVerdict(
+                false,
+                widget.widgetInfo != null
+                        ? widget.widgetInfo.provider.flattenToShortString()
+                        : widget.label,
+                String.format(Locale.ENGLISH, rejectionReason, args));
+    }
+
+    private static WidgetAcceptabilityVerdict acceptWidget(WidgetItem widget) {
+        return new WidgetAcceptabilityVerdict(
+                true, widget.widgetInfo.provider.flattenToShortString(), "");
+    }
+
+    private record WidgetAcceptabilityVerdict(
+            boolean isAcceptable, String widgetLabel, String reason) {
+        void maybeLogVerdict() {
+            // Only log a verdict if a reason is specified.
+            if (Log.isLoggable(TAG, Log.DEBUG) && !reason.isEmpty()) {
+                Log.i(TAG, String.format(
+                        Locale.ENGLISH,
+                        "%s: %s because %s",
+                        widgetLabel,
+                        isAcceptable ? "accepted" : "rejected",
+                        reason));
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 037f7a8..694475a 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -77,19 +77,15 @@
     public AppsDividerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        boolean isMainColorDark = Themes.getAttrBoolean(context, R.attr.isMainColorDark);
         mDividerSize = new int[]{
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_width),
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height)
         };
 
-        mStrokeColor = ContextCompat.getColor(context, isMainColorDark
-                ? R.color.all_apps_prediction_row_separator_dark
-                : R.color.all_apps_prediction_row_separator);
+        mStrokeColor = ContextCompat.getColor(context, R.color.material_color_outline_variant);
 
-        mAllAppsLabelTextColor = ContextCompat.getColor(context, isMainColorDark
-                ? R.color.all_apps_label_text_dark
-                : R.color.all_apps_label_text);
+        mAllAppsLabelTextColor = ContextCompat.getColor(context,
+                R.color.material_color_on_surface_variant);
 
         mShowAllAppsLabel = !ALL_APPS_VISITED_COUNT.hasReachedMax(context);
     }
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 1440498..70e01f5 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,13 +16,12 @@
 
 package com.android.launcher3.appprediction;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
 import androidx.annotation.NonNull;
@@ -31,12 +30,13 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.FloatingHeaderRow;
 import com.android.launcher3.allapps.FloatingHeaderView;
 import com.android.launcher3.anim.AlphaUpdateListener;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.keyboard.FocusIndicatorHelper;
 import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
 import com.android.launcher3.model.data.ItemInfo;
@@ -44,16 +44,21 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.views.ActivityContext;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
-@TargetApi(Build.VERSION_CODES.P)
 public class PredictionRowView<T extends Context & ActivityContext>
         extends LinearLayout implements OnDeviceProfileChangeListener, FloatingHeaderRow {
 
     private final T mActivityContext;
     private int mNumPredictedAppsPerRow;
+    // Vertical padding of the icon that contributes to the expected cell height.
+    private final int mVerticalPadding;
+    // Extra padding that is used in the top app rows (prediction and search) that is not used in
+    // the regular A-Z list. This only applies to single line label.
+    private final int mTopRowExtraHeight;
 
     // Helper to drawing the focus indicator.
     private final FocusIndicatorHelper mFocusHelper;
@@ -65,6 +70,8 @@
 
     private boolean mPredictionsEnabled = false;
 
+    private boolean mPredictionUiUpdatePaused = false;
+
     public PredictionRowView(@NonNull Context context) {
         this(context, null);
     }
@@ -76,6 +83,10 @@
         mFocusHelper = new SimpleFocusIndicatorHelper(this);
         mActivityContext = ActivityContext.lookupContext(context);
         mNumPredictedAppsPerRow = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
+        mTopRowExtraHeight = getResources().getDimensionPixelSize(
+                R.dimen.all_apps_search_top_row_extra_height);
+        mVerticalPadding = getResources().getDimensionPixelSize(
+                R.dimen.all_apps_predicted_icon_vertical_padding);
         updateVisibility();
     }
 
@@ -124,13 +135,13 @@
         int iconHeight = deviceProfile.allAppsIconSizePx;
         int iconPadding = deviceProfile.allAppsIconDrawablePaddingPx;
         int textHeight = Utilities.calculateTextHeight(deviceProfile.allAppsIconTextSizePx);
-        int verticalPadding = getResources().getDimensionPixelSize(
-                R.dimen.all_apps_predicted_icon_vertical_padding);
-        int totalHeight = iconHeight + iconPadding + textHeight + verticalPadding * 2;
-        if (FeatureFlags.enableTwolineAllapps()) {
-            // Add extra textHeight to the existing total height.
-            totalHeight += textHeight;
-        }
+        int totalHeight = iconHeight + iconPadding + textHeight + mVerticalPadding * 2;
+        // Prediction row height will be 4dp bigger than the regular apps in A-Z list when two line
+        // is not enabled. Otherwise, the extra height will increase by just the textHeight.
+        int extraHeight = (Flags.enableTwolineToggle() &&
+                LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext()))
+                ? textHeight : mTopRowExtraHeight;
+        totalHeight += extraHeight;
         return getVisibility() == GONE ? 0 : totalHeight + getPaddingTop() + getPaddingBottom();
     }
 
@@ -184,7 +195,18 @@
         applyPredictionApps();
     }
 
+    /** Pause the prediction row UI update */
+    public void setPredictionUiUpdatePaused(boolean predictionUiUpdatePaused) {
+        mPredictionUiUpdatePaused = predictionUiUpdatePaused;
+        if (!mPredictionUiUpdatePaused) {
+            applyPredictionApps();
+        }
+    }
+
     private void applyPredictionApps() {
+        if (mPredictionUiUpdatePaused) {
+            return;
+        }
         if (getChildCount() != mNumPredictedAppsPerRow) {
             while (getChildCount() > mNumPredictedAppsPerRow) {
                 removeViewAt(0);
@@ -199,8 +221,12 @@
                 icon.setOnFocusChangeListener(mFocusHelper);
 
                 LayoutParams lp = (LayoutParams) icon.getLayoutParams();
-                // Ensure the all apps icon height matches the workspace icons in portrait mode.
-                lp.height = mActivityContext.getDeviceProfile().allAppsCellHeightPx;
+                if (Flags.enableFocusOutline()) {
+                    lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
+                } else {
+                    // Ensure the all apps icon height matches the workspace icons in portrait mode.
+                    lp.height = mActivityContext.getDeviceProfile().allAppsCellHeightPx;
+                }
                 lp.width = 0;
                 lp.weight = 1;
                 addView(icon);
@@ -214,7 +240,11 @@
             icon.reset();
             if (predictionCount > i) {
                 icon.setVisibility(View.VISIBLE);
-                icon.applyFromWorkspaceItem(mPredictedApps.get(i));
+                WorkspaceItemInfo predictedItem = mPredictedApps.get(i);
+                predictedItem.rank = i;
+                predictedItem.cellX = i;
+                predictedItem.cellY = 0;
+                icon.applyFromWorkspaceItem(predictedItem);
             } else {
                 icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
             }
@@ -255,4 +285,11 @@
         return getChildAt(0);
     }
 
+    public void dump(String prefix, PrintWriter writer) {
+        writer.println(prefix + this.getClass().getSimpleName());
+        writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled);
+        writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused);
+        writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow);
+        writer.println(prefix + "\tmPredictedApps: " + mPredictedApps);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 10733fb..3ef8e54 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -20,9 +20,9 @@
 import android.os.RemoteException
 import android.util.Log
 import android.view.SurfaceControl
-import android.window.IRemoteTransition
 import android.window.IRemoteTransitionFinishedCallback
 import android.window.RemoteTransition
+import android.window.RemoteTransitionStub
 import android.window.TransitionInfo
 import com.android.launcher3.statehandlers.DepthController
 import com.android.launcher3.statemanager.StateManager
@@ -56,12 +56,17 @@
         systemUiProxy.showDesktopApps(desktopTaskView.display.displayId, transition)
     }
 
+    /** Launch desktop tasks from recents view */
+    fun moveToDesktop(taskId: Int) {
+        systemUiProxy.moveToDesktop(taskId)
+    }
+
     private class RemoteDesktopLaunchTransitionRunner(
         private val desktopTaskView: DesktopTaskView,
         private val stateManager: StateManager<*>,
         private val depthController: DepthController?,
         private val successCallback: Consumer<Boolean>?
-    ) : IRemoteTransition.Stub() {
+    ) : RemoteTransitionStub() {
 
         override fun startAnimation(
             token: IBinder,
@@ -90,17 +95,6 @@
                 }
             }
         }
-
-        override fun mergeAnimation(
-            transition: IBinder,
-            info: TransitionInfo,
-            t: SurfaceControl.Transaction,
-            mergeTarget: IBinder,
-            finishCallback: IRemoteTransitionFinishedCallback
-        ) {}
-
-        override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {
-        }
     }
 
     companion object {
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index baea418..1c5a75d 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -29,7 +29,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.ComponentName;
-import android.util.Log;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
 import android.view.ViewGroup;
@@ -41,6 +40,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
@@ -55,6 +55,7 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
@@ -79,7 +80,6 @@
         SystemShortcut.Factory<QuickstepLauncher>, DeviceProfile.OnDeviceProfileChangeListener,
         DragSource, ViewGroup.OnHierarchyChangeListener {
 
-    private static final String TAG = "HotseatPredictionController";
     private static final int FLAG_UPDATE_PAUSED = 1 << 0;
     private static final int FLAG_DRAG_IN_PROGRESS = 1 << 1;
     private static final int FLAG_FILL_IN_PROGRESS = 1 << 2;
@@ -188,7 +188,6 @@
     }
 
     private void fillGapsWithPrediction(boolean animate) {
-        Log.d(TAG, "fillGapsWithPrediction flags: " + getStateString(mPauseFlags));
         if (mPauseFlags != 0) {
             return;
         }
@@ -213,16 +212,12 @@
             View child = mHotseat.getChildAt(
                     mHotseat.getCellXFromOrder(rank),
                     mHotseat.getCellYFromOrder(rank));
-            Log.d(TAG, "Hotseat app child is: " + child + " and isPredictedIcon() evaluates to"
-                    + ": " + isPredictedIcon(child));
 
             if (child != null && !isPredictedIcon(child)) {
                 continue;
             }
             if (mPredictedItems.size() <= predictionIndex) {
                 // Remove predicted apps from the past
-                Log.d(TAG, "Remove predicted apps from the past\nPrediction Index: "
-                        + predictionIndex);
                 if (isPredictedIcon(child)) {
                     mHotseat.removeView(child);
                 }
@@ -230,11 +225,6 @@
             }
             WorkspaceItemInfo predictedItem =
                     (WorkspaceItemInfo) mPredictedItems.get(predictionIndex++);
-            Log.d(TAG, "Predicted item is: " + predictedItem);
-            if (child != null) {
-                Log.d(TAG, "Predicted item is enabled: " + child.isEnabled());
-            }
-
             if (isPredictedIcon(child) && child.isEnabled()) {
                 PredictedAppIcon icon = (PredictedAppIcon) child;
                 boolean animateIconChange = icon.shouldAnimateIconChange(predictedItem);
@@ -254,7 +244,6 @@
     }
 
     private void bindItems(List<WorkspaceItemInfo> itemsToAdd, boolean animate) {
-        Log.d(TAG, "bindItems to hotseat: " + itemsToAdd);
         AnimatorSet animationSet = new AnimatorSet();
         for (WorkspaceItemInfo item : itemsToAdd) {
             PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
@@ -294,7 +283,6 @@
      * start and pauses predicted apps update on the hotseat
      */
     public void setPauseUIUpdate(boolean paused) {
-        Log.d(TAG, "setPauseUIUpdate parameter `paused` is " + paused);
         mPauseFlags = paused
                 ? (mPauseFlags | FLAG_UPDATE_PAUSED)
                 : (mPauseFlags & ~FLAG_UPDATE_PAUSED);
@@ -309,10 +297,8 @@
     public void setPredictedItems(FixedContainerItems items) {
         mPredictedItems = new ArrayList(items.items);
         if (mPredictedItems.isEmpty()) {
-            Log.d(TAG, "Predicted items is initially empty");
             HotseatRestoreHelper.restoreBackup(mLauncher);
         }
-        Log.d(TAG, "Predicted items: " + mPredictedItems);
         fillGapsWithPrediction();
     }
 
@@ -417,6 +403,10 @@
         if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
             return null;
         }
+        if (Flags.enablePrivateSpace() && UserCache.getInstance(
+                activity.getApplicationContext()).getUserInfo(itemInfo.user).isPrivate()) {
+            return null;
+        }
         return new PinPrediction(activity, itemInfo, originalView);
     }
 
@@ -509,7 +499,7 @@
 
         @Override
         public void onClick(View view) {
-            dismissTaskMenuView(mTarget);
+            dismissTaskMenuView();
             pinPrediction(mItemInfo);
         }
     }
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 0dde1bd..a621259 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -25,6 +25,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
 import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_DRAGDROP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
@@ -37,20 +38,20 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
 import static com.android.launcher3.model.PredictionHelper.isTrackedForHotseatPrediction;
 import static com.android.launcher3.model.PredictionHelper.isTrackedForWidgetPrediction;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
-import android.annotation.TargetApi;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
 import android.app.prediction.AppTargetId;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ShortcutInfo;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Process;
@@ -71,17 +72,17 @@
 import com.android.launcher3.logging.StatsLogManager.EventEnum;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.util.UserIconInfo;
 import com.android.quickstep.logging.StatsLogCompatManager.StatsLogConsumer;
+import com.android.systemui.shared.system.SysUiStatsLog;
 
 import java.util.Locale;
 import java.util.Optional;
 import java.util.function.ObjIntConsumer;
-import java.util.function.Predicate;
 
 /**
  * Utility class to track stats log and emit corresponding app events
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class AppEventProducer implements StatsLogConsumer {
 
     private static final int MSG_LAUNCH = 0;
@@ -132,9 +133,11 @@
                 || event == LAUNCHER_TASK_LAUNCH_SWIPE_DOWN
                 || event == LAUNCHER_TASK_LAUNCH_TAP
                 || event == LAUNCHER_QUICKSWITCH_RIGHT
-                || event == LAUNCHER_QUICKSWITCH_LEFT) {
+                || event == LAUNCHER_QUICKSWITCH_LEFT
+                || event == LAUNCHER_APP_LAUNCH_DRAGDROP) {
             sendEvent(atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
-        } else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST) {
+        } else if (event == LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST
+                || event == LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP) {
             sendEvent(atomInfo, ACTION_DISMISS, CONTAINER_PREDICTION);
         } else if (event == LAUNCHER_ITEM_DRAG_STARTED) {
             mLastDragItem = atomInfo;
@@ -182,18 +185,21 @@
             sendEvent(target, atomInfo, ACTION_LAUNCH, CONTAINER_PREDICTION);
         } else if (event == LAUNCHER_DISMISS_PREDICTION_UNDO) {
             sendEvent(atomInfo, ACTION_UNDISMISS, CONTAINER_HOTSEAT_PREDICTION);
+        } else if (event == LAUNCHER_WIDGET_ADD_BUTTON_TAP) {
+            if (isTrackedForWidgetPrediction(atomInfo)) {
+                sendEvent(atomInfo, ACTION_PIN, CONTAINER_WIDGETS_PREDICTION);
+            }
         }
     }
 
     @Nullable
-    private AppTarget toAppTarget(LauncherAtom.ItemInfo info) {
-        UserHandle userHandle = Process.myUserHandle();
-        if (info.getIsWork()) {
-            userHandle = UserCache.INSTANCE.get(mContext).getUserProfiles().stream()
-                    .filter(((Predicate<UserHandle>) userHandle::equals).negate())
-                    .findAny()
-                    .orElse(null);
-        }
+    AppTarget toAppTarget(LauncherAtom.ItemInfo info) {
+        int iconInfoType = getIconInfoTypeFromItemInfo(info);
+        UserCache userCache = UserCache.INSTANCE.get(mContext);
+        UserHandle userHandle = userCache.getUserProfiles().stream()
+                .filter(user -> userCache.getUserInfo(user).type == iconInfoType)
+                .findFirst()
+                .orElse(null);
         if (userHandle == null) {
             return null;
         }
@@ -287,6 +293,9 @@
             case SHORTCUTS_CONTAINER: {
                 return "deep-shortcuts";
             }
+            case TASK_BAR_CONTAINER: {
+                return "taskbar";
+            }
             case FOLDER: {
                 FolderContainer fc = ci.getFolder();
                 switch (fc.getParentContainerCase()) {
@@ -323,4 +332,16 @@
         return TextUtils.isEmpty(componentNameString)
                 ? null : ComponentName.unflattenFromString(componentNameString);
     }
+
+    private int getIconInfoTypeFromItemInfo(LauncherAtom.ItemInfo info) {
+        int userType = info.getUserType();
+        return switch (userType) {
+            case SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_WORK -> UserIconInfo.TYPE_WORK;
+            case SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_CLONED ->
+                    UserIconInfo.TYPE_CLONED;
+            case SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_PRIVATE ->
+                    UserIconInfo.TYPE_PRIVATE;
+            default -> UserIconInfo.TYPE_MAIN;
+        };
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 667f784..65a49bd 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -18,8 +18,8 @@
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.formatElapsedTime;
 
-import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
@@ -65,10 +65,12 @@
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.IntSparseArrayMap;
 import com.android.launcher3.util.PersistedItemArray;
@@ -110,12 +112,11 @@
     private final InvariantDeviceProfile mIDP;
     private final AppEventProducer mAppEventProducer;
     private final StatsManager mStatsManager;
-    private final Context mContext;
 
     protected boolean mActive = false;
 
     public QuickstepModelDelegate(Context context) {
-        mContext = context;
+        super(context);
         mAppEventProducer = new AppEventProducer(context, this::onAppTargetEvent);
 
         mIDP = InvariantDeviceProfile.INSTANCE.get(context);
@@ -232,7 +233,7 @@
             }
             InstanceId instanceId = new InstanceIdSequence().newInstanceId();
             for (ItemInfo info : itemsIdMap) {
-                FolderInfo parent = getContainer(info, itemsIdMap);
+                CollectionInfo parent = getContainer(info, itemsIdMap);
                 StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
             }
             additionalSnapshotEvents(instanceId);
@@ -269,7 +270,7 @@
                         }
 
                         for (ItemInfo info : itemsIdMap) {
-                            FolderInfo parent = getContainer(info, itemsIdMap);
+                            CollectionInfo parent = getContainer(info, itemsIdMap);
                             LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
                             Log.d(TAG, itemInfo.toString());
                             StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
@@ -292,18 +293,19 @@
         }
     }
 
-    private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
+    private static CollectionInfo getContainer(
+            ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
         if (info.container > 0) {
             ItemInfo containerInfo = itemsIdMap.get(info.container);
 
-            if (!(containerInfo instanceof FolderInfo)) {
+            if (!(containerInfo instanceof CollectionInfo)) {
                 Log.e(TAG, String.format(
                         "Item info: %s found with invalid container: %s",
                         info,
                         containerInfo));
             }
             // Allow crash to help debug b/173838775
-            return (FolderInfo) containerInfo;
+            return (CollectionInfo) containerInfo;
         }
         return null;
     }
@@ -324,8 +326,12 @@
         super.destroy();
         mActive = false;
         StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
-        if (mIsPrimaryInstance) {
-            mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+        if (mIsPrimaryInstance && mStatsManager != null) {
+            try {
+                mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Failed to unregister snapshot logging callback with StatsManager", e);
+            }
         }
         destroyPredictors();
     }
@@ -553,7 +559,11 @@
                     if (lai == null) {
                         return null;
                     }
-                    AppInfo info = new AppInfo(lai, user, mUMS.isUserQuiet(user));
+                    AppInfo info = new AppInfo(
+                            lai,
+                            UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user),
+                            ApiWrapper.INSTANCE.get(mAppState.getContext()),
+                            mUMS.isUserQuiet(user));
                     info.container = mContainer;
                     mAppState.getIconCache().getTitleAndIcon(info, lai, false);
                     mReadCount++;
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 003c2fc..a7c9652 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -20,7 +20,6 @@
 
 import static com.android.launcher3.util.SimpleBroadcastReceiver.getPackageFilter;
 
-import android.annotation.TargetApi;
 import android.app.RemoteAction;
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -30,11 +29,9 @@
 import android.content.pm.LauncherApps;
 import android.database.ContentObserver;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
@@ -46,15 +43,16 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.popup.RemoteActionShortcut;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.BgObjectWithLooper;
+import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.Arrays;
 import java.util.HashMap;
@@ -63,8 +61,7 @@
 /**
  * Data model for digital wellbeing status of apps.
  */
-@TargetApi(Build.VERSION_CODES.Q)
-public final class WellbeingModel extends BgObjectWithLooper {
+public final class WellbeingModel implements SafeCloseable {
     private static final String TAG = "WellbeingModel";
     private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
     private static final boolean DEBUG = false;
@@ -84,8 +81,12 @@
     private final Context mContext;
     private final String mWellbeingProviderPkg;
 
-    private Handler mWorkerHandler;
-    private ContentObserver mContentObserver;
+    private final Handler mWorkerHandler;
+    private final ContentObserver mContentObserver;
+    private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
+            new SimpleBroadcastReceiver(t -> restartObserver());
+    private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
+            new SimpleBroadcastReceiver(this::onAppPackageChanged);
 
     private final Object mModelLock = new Object();
     // Maps the action Id to the corresponding RemoteAction
@@ -97,16 +98,23 @@
     private WellbeingModel(final Context context) {
         mContext = context;
         mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
-        initializeInBackground("WellbeingHandler");
+        mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
+                ? Executors.UI_HELPER_EXECUTOR.getLooper()
+                : Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
+
+        mContentObserver = new ContentObserver(mWorkerHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri) {
+                updateAllPackages();
+            }
+        };
+        mWorkerHandler.post(this::initializeInBackground);
     }
 
-    @Override
-    protected void onInitialized(Looper looper) {
-        mWorkerHandler = new Handler(looper);
-        mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
+    private void initializeInBackground() {
         if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
             mContext.registerReceiver(
-                    new SimpleBroadcastReceiver(t -> restartObserver()),
+                    mWellbeingAppChangeReceiver,
                     getPackageFilter(mWellbeingProviderPkg,
                             Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
                             Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
@@ -116,17 +124,21 @@
             IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
             filter.addDataScheme("package");
-            mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
-                    filter, null, mWorkerHandler);
+            mContext.registerReceiver(mAppAddRemoveReceiver, filter, null, mWorkerHandler);
 
             restartObserver();
         }
     }
 
-    @WorkerThread
-    private void onWellbeingUriChanged(Uri uri) {
-        Preconditions.assertNonUiThread();
-        updateAllPackages();
+    @Override
+    public void close() {
+        if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
+            mWorkerHandler.post(() -> {
+                mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
+                mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
+                mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+            });
+        }
     }
 
     public void setInTest(boolean inTest) {
@@ -150,7 +162,7 @@
 
     @MainThread
     private SystemShortcut getShortcutForApp(String packageName, int userId,
-            BaseDraggingActivity activity, ItemInfo info, View originalView) {
+            Context context, ItemInfo info, View originalView) {
         Preconditions.assertUIThread();
         // Work profile apps are not recognized by digital wellbeing.
         if (userId != UserHandle.myUserId()) {
@@ -174,7 +186,7 @@
                         "getShortcutForApp [" + packageName + "]: action: '" + action.getTitle()
                                 + "'");
             }
-            return new RemoteActionShortcut(action, activity, info, originalView);
+            return new RemoteActionShortcut(action, context, info, originalView);
         }
     }
 
@@ -308,9 +320,11 @@
     /**
      * Shortcut factory for generating wellbeing action
      */
-    public static final SystemShortcut.Factory<BaseDraggingActivity> SHORTCUT_FACTORY =
-            (activity, info, originalView) -> (info.getTargetComponent() == null) ? null
-                    : INSTANCE.get(activity).getShortcutForApp(
-                            info.getTargetComponent().getPackageName(), info.user.getIdentifier(),
-                            activity, info, originalView);
+    public static final SystemShortcut.Factory<ActivityContext> SHORTCUT_FACTORY =
+            (context, info, originalView) ->
+                    (info.getTargetComponent() == null) ? null
+                            : INSTANCE.get(originalView.getContext()).getShortcutForApp(
+                                    info.getTargetComponent().getPackageName(), info.user.getIdentifier(),
+                                    ActivityContext.lookupContext(originalView.getContext()),
+                                    info, originalView);
 }
diff --git a/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
new file mode 100644
index 0000000..8431396
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/model/WidgetPredictionsRequester.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import android.app.prediction.AppPredictionContext;
+import android.app.prediction.AppPredictionManager;
+import android.app.prediction.AppPredictor;
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetEvent;
+import android.app.prediction.AppTargetId;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.picker.WidgetRecommendationCategoryProvider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * Works with app predictor to fetch and process widget predictions displayed in a standalone
+ * widget picker activity for a UI surface.
+ */
+public class WidgetPredictionsRequester {
+    private static final int NUM_OF_RECOMMENDED_WIDGETS_PREDICATION = 20;
+    private static final String BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets";
+
+    @Nullable
+    private AppPredictor mAppPredictor;
+    private final Context mContext;
+    @NonNull
+    private final String mUiSurface;
+    @NonNull
+    private final Map<PackageUserKey, List<WidgetItem>> mAllWidgets;
+
+    public WidgetPredictionsRequester(Context context, @NonNull String uiSurface,
+            @NonNull Map<PackageUserKey, List<WidgetItem>> allWidgets) {
+        mContext = context;
+        mUiSurface = uiSurface;
+        mAllWidgets = Collections.unmodifiableMap(allWidgets);
+    }
+
+    /**
+     * Requests predictions from the app predictions manager and registers the provided callback to
+     * receive updates when predictions are available.
+     *
+     * @param existingWidgets widgets that are currently added to the surface;
+     * @param callback        consumer of prediction results to be called when predictions are
+     *                        available
+     */
+    public void request(List<AppWidgetProviderInfo> existingWidgets,
+            Consumer<List<ItemInfo>> callback) {
+        Bundle bundle = buildBundleForPredictionSession(existingWidgets, mUiSurface);
+        Predicate<WidgetItem> filter = notOnUiSurfaceFilter(existingWidgets);
+
+        MODEL_EXECUTOR.execute(() -> {
+            clear();
+            AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class);
+            if (apm == null) {
+                return;
+            }
+
+            mAppPredictor = apm.createAppPredictionSession(
+                    new AppPredictionContext.Builder(mContext)
+                            .setUiSurface(mUiSurface)
+                            .setExtras(bundle)
+                            .setPredictedTargetCount(NUM_OF_RECOMMENDED_WIDGETS_PREDICATION)
+                            .build());
+            mAppPredictor.registerPredictionUpdates(MODEL_EXECUTOR,
+                    targets -> bindPredictions(targets, filter, callback));
+            mAppPredictor.requestPredictionUpdate();
+        });
+    }
+
+    /**
+     * Returns a bundle that can be passed in a prediction session
+     *
+     * @param addedWidgets widgets that are already added by the user in the ui surface
+     * @param uiSurface    a unique identifier of the surface hosting widgets; format
+     *                     "widgets_xx"; note - "widgets" is reserved for home screen surface.
+     */
+    @VisibleForTesting
+    static Bundle buildBundleForPredictionSession(List<AppWidgetProviderInfo> addedWidgets,
+            String uiSurface) {
+        Bundle bundle = new Bundle();
+        ArrayList<AppTargetEvent> addedAppTargetEvents = new ArrayList<>();
+        for (AppWidgetProviderInfo info : addedWidgets) {
+            ComponentName componentName = info.provider;
+            AppTargetEvent appTargetEvent = buildAppTargetEvent(uiSurface, info, componentName);
+            addedAppTargetEvents.add(appTargetEvent);
+        }
+        bundle.putParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, addedAppTargetEvents);
+        return bundle;
+    }
+
+    /**
+     * Builds the AppTargetEvent for added widgets in a form that can be passed to the widget
+     * predictor.
+     * Also see {@link PredictionHelper}
+     */
+    private static AppTargetEvent buildAppTargetEvent(String uiSurface, AppWidgetProviderInfo info,
+            ComponentName componentName) {
+        AppTargetId appTargetId = new AppTargetId("widget:" + componentName.getPackageName());
+        AppTarget appTarget = new AppTarget.Builder(appTargetId, componentName.getPackageName(),
+                /*user=*/ info.getProfile()).setClassName(componentName.getClassName()).build();
+        return new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_PIN)
+                .setLaunchLocation(uiSurface).build();
+    }
+
+    /**
+     * Returns a filter to match {@link WidgetItem}s that don't exist on the UI surface.
+     */
+    @NonNull
+    @VisibleForTesting
+    static Predicate<WidgetItem> notOnUiSurfaceFilter(
+            List<AppWidgetProviderInfo> existingWidgets) {
+        Set<ComponentKey> existingComponentKeys = existingWidgets.stream().map(
+                widget -> new ComponentKey(widget.provider, widget.getProfile())).collect(
+                Collectors.toSet());
+        return widgetItem -> !existingComponentKeys.contains(widgetItem);
+    }
+
+    /** Provides the predictions returned by the predictor to the registered callback. */
+    @WorkerThread
+    private void bindPredictions(List<AppTarget> targets, Predicate<WidgetItem> filter,
+            Consumer<List<ItemInfo>> callback) {
+        List<WidgetItem> filteredPredictions = filterPredictions(targets, mAllWidgets, filter);
+        List<ItemInfo> mappedPredictions = mapWidgetItemsToItemInfo(filteredPredictions);
+
+        MAIN_EXECUTOR.execute(() -> callback.accept(mappedPredictions));
+    }
+
+    /**
+     * Applies the provided filter (e.g. widgets not on workspace) on the predictions returned by
+     * the predictor.
+     */
+    @VisibleForTesting
+    static List<WidgetItem> filterPredictions(List<AppTarget> predictions,
+            Map<PackageUserKey, List<WidgetItem>> allWidgets, Predicate<WidgetItem> filter) {
+        List<WidgetItem> servicePredictedItems = new ArrayList<>();
+        List<WidgetItem> localFilteredWidgets = new ArrayList<>();
+
+        for (AppTarget prediction : predictions) {
+            List<WidgetItem> widgetsInPackage = allWidgets.get(
+                    new PackageUserKey(prediction.getPackageName(), prediction.getUser()));
+            if (widgetsInPackage == null || widgetsInPackage.isEmpty()) {
+                continue;
+            }
+            String className = prediction.getClassName();
+            if (!TextUtils.isEmpty(className)) {
+                WidgetItem item = widgetsInPackage.stream()
+                        .filter(w -> className.equals(w.componentName.getClassName()))
+                        .filter(filter)
+                        .findFirst().orElse(null);
+                if (item != null) {
+                    servicePredictedItems.add(item);
+                    continue;
+                }
+            }
+            // No widget was added by the service, try local filtering
+            widgetsInPackage.stream().filter(filter).findFirst()
+                    .ifPresent(localFilteredWidgets::add);
+        }
+        if (servicePredictedItems.isEmpty()) {
+            servicePredictedItems.addAll(localFilteredWidgets);
+        }
+
+        return servicePredictedItems;
+    }
+
+    /**
+     * Converts the list of {@link WidgetItem}s to the list of {@link ItemInfo}s.
+     */
+    private List<ItemInfo> mapWidgetItemsToItemInfo(List<WidgetItem> widgetItems) {
+        List<ItemInfo> items;
+        if (enableCategorizedWidgetSuggestions()) {
+            WidgetRecommendationCategoryProvider categoryProvider =
+                    WidgetRecommendationCategoryProvider.newInstance(mContext);
+            items = widgetItems.stream()
+                    .map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION,
+                            categoryProvider.getWidgetRecommendationCategory(mContext, it)))
+                    .collect(Collectors.toList());
+        } else {
+            items = widgetItems.stream().map(it -> new PendingAddWidgetInfo(it.widgetInfo,
+                    CONTAINER_WIDGETS_PREDICTION)).collect(Collectors.toList());
+        }
+        return items;
+    }
+
+    /** Cleans up any open prediction sessions. */
+    public void clear() {
+        if (mAppPredictor != null) {
+            mAppPredictor.destroy();
+            mAppPredictor = null;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 6160378..f4cbf17 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -15,9 +15,11 @@
  */
 package com.android.launcher3.model;
 
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
 
 import android.app.prediction.AppTarget;
+import android.content.Context;
 import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
@@ -29,6 +31,7 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.picker.WidgetRecommendationCategoryProvider;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -93,9 +96,21 @@
             servicePredictedItems.addAll(localFilteredWidgets);
         }
 
-        List<ItemInfo> items = servicePredictedItems.stream()
-                .map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION))
-                .collect(Collectors.toList());
+        List<ItemInfo> items;
+        if (enableCategorizedWidgetSuggestions()) {
+            Context context = appState.getContext();
+            WidgetRecommendationCategoryProvider categoryProvider =
+                    WidgetRecommendationCategoryProvider.newInstance(context);
+            items = servicePredictedItems.stream()
+                    .map(it -> new PendingAddWidgetInfo(it.widgetInfo, CONTAINER_WIDGETS_PREDICTION,
+                            categoryProvider.getWidgetRecommendationCategory(context, it)))
+                    .collect(Collectors.toList());
+        } else {
+            items = servicePredictedItems.stream()
+                    .map(it -> new PendingAddWidgetInfo(it.widgetInfo,
+                            CONTAINER_WIDGETS_PREDICTION)).collect(
+                            Collectors.toList());
+        }
         FixedContainerItems fixedContainerItems =
                 new FixedContainerItems(mPredictorState.containerId, items);
 
diff --git a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
index 6d90b035..212a5ff 100644
--- a/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
+++ b/quickstep/src/com/android/launcher3/proxy/ProxyActivityStarter.java
@@ -53,13 +53,10 @@
 
         try {
             if (mParams.intent != null) {
-                startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
+                startActivity();
                 return;
             } else if (mParams.intentSender != null) {
-                startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
-                        mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
-                        mParams.extraFlags,
-                        mParams.options);
+                startIntentSender();
                 return;
             }
         } catch (NullPointerException | ActivityNotFoundException | SecurityException
@@ -83,4 +80,26 @@
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                         | Intent.FLAG_ACTIVITY_CLEAR_TASK);
     }
+
+    private void startActivity() throws SendIntentException {
+        if (mParams.requireActivityResult) {
+            startActivityForResult(mParams.intent, mParams.requestCode, mParams.options);
+        } else {
+            startActivity(mParams.intent, mParams.options);
+            finishAndRemoveTask();
+        }
+    }
+
+    private void startIntentSender() throws SendIntentException {
+        if (mParams.requireActivityResult) {
+            startIntentSenderForResult(mParams.intentSender, mParams.requestCode,
+                    mParams.fillInIntent, mParams.flagsMask, mParams.flagsValues,
+                    mParams.extraFlags,
+                    mParams.options);
+        } else {
+            startIntentSender(mParams.intentSender, mParams.fillInIntent, mParams.flagsMask,
+                    mParams.flagsValues, mParams.extraFlags, mParams.options);
+            finishAndRemoveTask();
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index a7e8118..5ac5761 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -15,9 +15,11 @@
  */
 package com.android.launcher3.statehandlers;
 
+import static android.view.View.VISIBLE;
+
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.os.Debug;
 import android.os.SystemProperties;
@@ -35,6 +37,9 @@
 import com.android.quickstep.views.DesktopAppSelectView;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Controls the visibility of the workspace and the resumed / paused state when desktop mode
  * is enabled.
@@ -46,8 +51,9 @@
     private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_stashing", false);
     private final Launcher mLauncher;
+    private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
 
-    private boolean mFreeformTasksVisible;
+    private int mVisibleDesktopTasksCount;
     private boolean mInOverviewState;
     private boolean mBackgroundStateEnabled;
     private boolean mGestureInProgress;
@@ -66,13 +72,13 @@
     public void registerSystemUiListener() {
         mDesktopTaskListener = new IDesktopTaskListener.Stub() {
             @Override
-            public void onVisibilityChanged(int displayId, boolean visible) {
+            public void onTasksVisibilityChanged(int displayId, int visibleTasksCount) {
                 MAIN_EXECUTOR.execute(() -> {
                     if (displayId == mLauncher.getDisplayId()) {
                         if (DEBUG) {
-                            Log.d(TAG, "desktop visibility changed value=" + visible);
+                            Log.d(TAG, "desktop visible tasks count changed=" + visibleTasksCount);
                         }
-                        setFreeformTasksVisible(visible);
+                        setVisibleDesktopTasksCount(visibleTasksCount);
                     }
                 });
             }
@@ -107,42 +113,69 @@
     }
 
     /**
-     * Whether freeform windows are visible in desktop mode.
+     * Whether desktop tasks are visible in desktop mode.
      */
-    public boolean areFreeformTasksVisible() {
+    public boolean areDesktopTasksVisible() {
+        boolean desktopTasksVisible = mVisibleDesktopTasksCount > 0;
         if (DEBUG) {
-            Log.d(TAG, "areFreeformTasksVisible: freeformVisible=" + mFreeformTasksVisible
+            Log.d(TAG, "areDesktopTasksVisible: desktopVisible=" + desktopTasksVisible
                     + " overview=" + mInOverviewState);
         }
-        return mFreeformTasksVisible && !mInOverviewState;
+        return desktopTasksVisible && !mInOverviewState;
     }
 
     /**
-     * Sets whether freeform windows are visible and updates launcher visibility based on that.
+     * Number of visible desktop windows in desktop mode.
      */
-    public void setFreeformTasksVisible(boolean freeformTasksVisible) {
+    public int getVisibleDesktopTasksCount() {
+        return mVisibleDesktopTasksCount;
+    }
+
+    /** Registers a listener for Desktop Mode visibility updates. */
+    public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
+        mDesktopVisibilityListeners.add(listener);
+    }
+
+    /** Removes a previously registered Desktop Mode visibility listener. */
+    public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
+        mDesktopVisibilityListeners.remove(listener);
+    }
+
+    /**
+     * Sets the number of desktop windows that are visible and updates launcher visibility based on
+     * it.
+     */
+    public void setVisibleDesktopTasksCount(int visibleTasksCount) {
         if (DEBUG) {
-            Log.d(TAG, "setFreeformTasksVisible: visible=" + freeformTasksVisible
-                    + " currentValue=" + mFreeformTasksVisible);
-        }
-        if (!isDesktopModeSupported()) {
-            return;
+            Log.d(TAG, "setVisibleDesktopTasksCount: visibleTasksCount=" + visibleTasksCount
+                    + " currentValue=" + mVisibleDesktopTasksCount);
         }
 
-        if (freeformTasksVisible != mFreeformTasksVisible) {
-            mFreeformTasksVisible = freeformTasksVisible;
-            if (mFreeformTasksVisible) {
-                setLauncherViewsVisibility(View.INVISIBLE);
-                if (!mInOverviewState) {
-                    // When freeform is visible & we're not in overview, we want launcher to appear
-                    // paused, this ensures that taskbar displays.
-                    markLauncherPaused();
+        if (visibleTasksCount != mVisibleDesktopTasksCount) {
+            final boolean wasVisible = mVisibleDesktopTasksCount > 0;
+            final boolean isVisible = visibleTasksCount > 0;
+            final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
+            mVisibleDesktopTasksCount = visibleTasksCount;
+            final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+            if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+                notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+            }
+
+            if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
+                // TODO: b/333533253 - Remove after flag rollout
+                if (mVisibleDesktopTasksCount > 0) {
+                    setLauncherViewsVisibility(View.INVISIBLE);
+                    if (!mInOverviewState) {
+                        // When desktop tasks are visible & we're not in overview, we want launcher
+                        // to appear paused, this ensures that taskbar displays.
+                        markLauncherPaused();
+                    }
+                } else {
+                    setLauncherViewsVisibility(View.VISIBLE);
+                    // If desktop tasks aren't visible, ensure that launcher appears resumed to
+                    // behave normally.
+                    markLauncherResumed();
                 }
-            } else {
-                setLauncherViewsVisibility(View.VISIBLE);
-                // If freeform isn't visible ensure that launcher appears resumed to behave
-                // normally.
-                markLauncherResumed();
             }
         }
     }
@@ -164,38 +197,55 @@
             Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled
                     + " currentValue=" + mInOverviewState);
         }
-        if (!isDesktopModeSupported()) {
-            return;
-        }
         if (overviewStateEnabled != mInOverviewState) {
+            final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
             mInOverviewState = overviewStateEnabled;
+            final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+            if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+                notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+            }
+
+            if (enableDesktopWindowingWallpaperActivity()) {
+                return;
+            }
+            // TODO: b/333533253 - Clean up after flag rollout
+
             if (mInOverviewState) {
                 setLauncherViewsVisibility(View.VISIBLE);
                 markLauncherResumed();
-            } else if (areFreeformTasksVisible() && !mGestureInProgress) {
+            } else if (areDesktopTasksVisibleNow && !mGestureInProgress) {
                 // Switching out of overview state and gesture finished.
-                // If freeform tasks are still visible, hide launcher again.
+                // If desktop tasks are still visible, hide launcher again.
                 setLauncherViewsVisibility(View.INVISIBLE);
                 markLauncherPaused();
             }
         }
     }
 
+    private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+        if (DEBUG) {
+            Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
+        }
+        for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
+            listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
+        }
+    }
+
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setBackgroundStateEnabled(boolean backgroundStateEnabled) {
         if (DEBUG) {
             Log.d(TAG, "setBackgroundStateEnabled: enabled=" + backgroundStateEnabled
                     + " currentValue=" + mBackgroundStateEnabled);
         }
-        if (!isDesktopModeSupported()) {
-            return;
-        }
         if (backgroundStateEnabled != mBackgroundStateEnabled) {
             mBackgroundStateEnabled = backgroundStateEnabled;
             if (mBackgroundStateEnabled) {
                 setLauncherViewsVisibility(View.VISIBLE);
                 markLauncherResumed();
-            } else if (areFreeformTasksVisible() && !mGestureInProgress) {
-                // Switching out of background state. If freeform tasks are visible, pause launcher.
+            } else if (areDesktopTasksVisible() && !mGestureInProgress) {
+                // Switching out of background state. If desktop tasks are visible, pause launcher.
                 setLauncherViewsVisibility(View.INVISIBLE);
                 markLauncherPaused();
             }
@@ -204,6 +254,8 @@
 
     /**
      * Whether recents gesture is currently in progress.
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public boolean isRecentsGestureInProgress() {
         return mGestureInProgress;
@@ -211,11 +263,10 @@
 
     /**
      * Notify controller that recents gesture has started.
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public void setRecentsGestureStart() {
-        if (!isDesktopModeSupported()) {
-            return;
-        }
         if (DEBUG) {
             Log.d(TAG, "setRecentsGestureStart");
         }
@@ -225,11 +276,10 @@
     /**
      * Notify controller that recents gesture finished with the given
      * {@link com.android.quickstep.GestureState.GestureEndTarget}
+     *
+     * TODO: b/333533253 - Remove after flag rollout
      */
     public void setRecentsGestureEnd(@Nullable GestureState.GestureEndTarget endTarget) {
-        if (!isDesktopModeSupported()) {
-            return;
-        }
         if (DEBUG) {
             Log.d(TAG, "setRecentsGestureEnd: endTarget=" + endTarget);
         }
@@ -241,6 +291,9 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setRecentsGestureInProgress(boolean gestureInProgress) {
         if (gestureInProgress != mGestureInProgress) {
             mGestureInProgress = gestureInProgress;
@@ -251,12 +304,18 @@
      * Handle launcher moving to home due to home gesture or home button press.
      */
     public void onHomeActionTriggered() {
-        if (IS_STASHING_ENABLED && areFreeformTasksVisible()) {
+        if (IS_STASHING_ENABLED && areDesktopTasksVisible()) {
             SystemUiProxy.INSTANCE.get(mLauncher).stashDesktopApps(mLauncher.getDisplayId());
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void setLauncherViewsVisibility(int visibility) {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " "
                     + Debug.getCaller());
@@ -269,9 +328,19 @@
         if (dragLayer != null) {
             dragLayer.setVisibility(visibility);
         }
+        if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null
+                && mVisibleDesktopTasksCount != 0) {
+            ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE);
+        }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void markLauncherPaused() {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "markLauncherPaused " + Debug.getCaller());
         }
@@ -282,7 +351,13 @@
         }
     }
 
+    /**
+     * TODO: b/333533253 - Remove after flag rollout
+     */
     private void markLauncherResumed() {
+        if (enableDesktopWindowingWallpaperActivity()) {
+            return;
+        }
         if (DEBUG) {
             Log.d(TAG, "markLauncherResumed " + Debug.getCaller());
         }
@@ -319,4 +394,14 @@
         mSelectAppToast.hide();
         mSelectAppToast = null;
     }
+
+    /** A listener for when the user enters/exits Desktop Mode. */
+    public interface DesktopVisibilityListener {
+        /**
+         * Callback for when the user enters or exits Desktop Mode
+         *
+         * @param visible whether Desktop Mode is now visible
+         */
+        void onDesktopVisibilityChanged(boolean visible);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt b/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt
new file mode 100644
index 0000000..8aee1aa
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.PixelFormat
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.DrawableWrapper
+
+/* BitmapDrawable that can blur the given bitmap. */
+class BlurredBitmapDrawable(bitmap: Bitmap?, radiusX: Float, radiusY: Float) :
+    DrawableWrapper(BitmapDrawable(bitmap)) {
+    private val mBlurRenderNode: RenderNode = RenderNode("BlurredConstraintLayoutBlurNode")
+
+    constructor(bitmap: Bitmap?, radius: Float) : this(bitmap, radius, radius)
+
+    init {
+        mBlurRenderNode.setRenderEffect(
+            RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.CLAMP)
+        )
+    }
+
+    override fun draw(canvas: Canvas) {
+        if (!canvas.isHardwareAccelerated) {
+            super.draw(canvas)
+            return
+        }
+        mBlurRenderNode.setPosition(bounds)
+        if (!mBlurRenderNode.hasDisplayList()) {
+            // Record render node if its display list is not recorded or discarded
+            // (which happens when it's no longer drawn by anything).
+            val recordingCanvas = mBlurRenderNode.beginRecording()
+            super.draw(recordingCanvas)
+            mBlurRenderNode.endRecording()
+        }
+        canvas.drawRenderNode(mBlurRenderNode)
+    }
+
+    override fun getOpacity(): Int {
+        return PixelFormat.OPAQUE
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
index 0a9dfff..3635827 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
@@ -28,6 +28,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
 
 /**
  * Controller for managing buttons and status icons in taskbar in a desktop environment.
@@ -43,7 +44,7 @@
     private TaskbarControllers mControllers;
 
     public DesktopNavbarButtonsViewController(TaskbarActivityContext context,
-            @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
+            @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
         super(context, navigationBarPanelContext, navButtonsView);
         mContext = context;
         mNavButtonsView = navButtonsView;
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
new file mode 100644
index 0000000..f665e21
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import android.util.Log
+import android.util.SparseArray
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.valueIterator
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import kotlin.collections.filterNotNull
+
+/**
+ * Shows running apps when in Desktop Mode.
+ *
+ * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
+ * recent-apps behaviour when outside of Desktop Mode.
+ *
+ * This class should only be used if
+ * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
+ */
+class DesktopTaskbarRunningAppsController(
+    private val recentsModel: RecentsModel,
+    private val desktopVisibilityController: DesktopVisibilityController?,
+) : TaskbarRecentAppsController() {
+
+    private var apps: Array<AppInfo>? = null
+    private var allRunningDesktopAppInfos: List<AppInfo>? = null
+    private var runningDesktopAppInfosExceptHotseatItems: List<ItemInfo>? = null
+
+    private val isInDesktopMode: Boolean
+        get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
+
+    override fun onDestroy() {
+        super.onDestroy()
+        apps = null
+    }
+
+    @VisibleForTesting
+    public override fun setApps(apps: Array<AppInfo>?) {
+        this.apps = apps
+    }
+
+    override fun isEnabled() = true
+
+    @VisibleForTesting
+    public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo>?): Array<ItemInfo>? {
+        val actualHotseatItems = hotseatItems ?: return super.updateHotseatItemInfos(null)
+        if (!isInDesktopMode) {
+            Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
+            return hotseatItems
+        }
+        val newHotseatItemInfos =
+            actualHotseatItems
+                // Ignore predicted apps - we show running apps instead
+                .filter { itemInfo -> !itemInfo.isPredictedItem }
+                .toMutableList()
+        val runningDesktopAppInfos =
+            runningDesktopAppInfosExceptHotseatItems ?: return newHotseatItemInfos.toTypedArray()
+        newHotseatItemInfos.addAll(runningDesktopAppInfos)
+        return newHotseatItemInfos.toTypedArray()
+    }
+
+    @VisibleForTesting
+    public override fun updateRunningApps(hotseatItems: SparseArray<ItemInfo>?) {
+        if (!isInDesktopMode) {
+            Log.d(TAG, "updateRunningApps: not in Desktop Mode")
+            mControllers.taskbarViewController.commitRunningAppsToUI()
+            return
+        }
+        val allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+        this.allRunningDesktopAppInfos = allRunningDesktopAppInfos
+        runningDesktopAppInfosExceptHotseatItems =
+            hotseatItems?.let {
+                getRunningDesktopAppInfosExceptHotseatApps(allRunningDesktopAppInfos, it.toList())
+            }
+
+        mControllers.taskbarViewController.commitRunningAppsToUI()
+    }
+
+    private fun getRunningDesktopAppInfosExceptHotseatApps(
+        allRunningDesktopAppInfos: List<AppInfo>,
+        hotseatItems: List<ItemInfo>
+    ): List<ItemInfo> {
+        val hotseatPackages = hotseatItems.map { it.targetPackage }
+        return allRunningDesktopAppInfos
+            .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
+            .map { WorkspaceItemInfo(it) }
+    }
+
+    private fun getRunningDesktopAppInfos(): List<AppInfo> {
+        return getAppInfosFromRunningTasks(
+            recentsModel.runningTasks
+                .filter { taskInfo: RunningTaskInfo ->
+                    taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+                }
+                .toList()
+        )
+    }
+
+    // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
+    private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
+        // Early return if apps is empty, since we then have no AppInfo to compare to
+        if (apps == null) {
+            return emptyList()
+        }
+        val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
+        return packageNames
+            .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
+            .filterNotNull()
+    }
+
+    private fun <E> SparseArray<E>.toList(): List<E> {
+        return valueIterator().asSequence().toList()
+    }
+
+    companion object {
+        private const val TAG = "TabletDesktopTaskbarRunningAppsController"
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
index 633325b..2dd610c4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarUIController.java
@@ -16,7 +16,10 @@
 
 package com.android.launcher3.taskbar;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.quickstep.util.TISBindHelper;
 
 /**
  * A data source which integrates with a Launcher instance, used specifically for a
@@ -50,4 +53,10 @@
     public boolean supportsVisualStashing() {
         return false;
     }
+
+    @Nullable
+    @Override
+    protected TISBindHelper getTISBindHelper() {
+        return mLauncher.getTISBindHelper();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index f981610..c0ecc61 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -21,11 +21,14 @@
 
 import android.animation.Animator;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
 
 import java.util.stream.Stream;
@@ -124,4 +127,10 @@
                 .get(mControllers.taskbarActivityContext).getCachedTopTask(true);
         return topTask.isHomeTask() || topTask.isRecentsTask();
     }
+
+    @Nullable
+    @Override
+    protected TISBindHelper getTISBindHelper() {
+        return mRecentsActivity.getTISBindHelper();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index f58fd45..b213203 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -15,13 +15,12 @@
  */
 package com.android.launcher3.taskbar;
 
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.R;
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
@@ -32,6 +31,7 @@
 import com.android.quickstep.util.GroupTask;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -46,7 +46,8 @@
 public final class KeyboardQuickSwitchController implements
         TaskbarControllers.LoggableTaskbarController {
 
-    static final int MAX_TASKS = 6;
+    @VisibleForTesting
+    public static final int MAX_TASKS = 6;
 
     @NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks();
 
@@ -94,7 +95,11 @@
 
     private void openQuickSwitchView(int currentFocusedIndex) {
         if (mQuickSwitchViewController != null) {
-            return;
+            if (!mQuickSwitchViewController.isCloseAnimationRunning()) {
+                return;
+            }
+            // Allow the KQS to be reopened during the close animation to make it more responsive
+            closeQuickSwitchView(false);
         }
         TaskbarOverlayContext overlayContext =
                 mControllers.taskbarOverlayController.requestWindow();
@@ -110,13 +115,18 @@
         DesktopVisibilityController desktopController =
                 LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
         final boolean onDesktop =
-                isDesktopModeSupported()
-                        && desktopController != null
-                        && desktopController.areFreeformTasksVisible();
+                desktopController != null && desktopController.areDesktopTasksVisible();
 
         if (mModel.isTaskListValid(mTaskListChangeId)) {
-            mQuickSwitchViewController.openQuickSwitchView(mTasks,
-                    mNumHiddenTasks, /* updateTasks= */ false, currentFocusedIndex, onDesktop);
+            // When we are opening the KQS with no focus override, check if the first task is
+            // running. If not, focus that first task.
+            mQuickSwitchViewController.openQuickSwitchView(
+                    mTasks,
+                    mNumHiddenTasks,
+                    /* updateTasks= */ false,
+                    currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
+                            ? 0 : currentFocusedIndex,
+                    onDesktop);
             return;
         }
 
@@ -126,30 +136,25 @@
             } else {
                 processLoadedTasks(tasks);
             }
-            mQuickSwitchViewController.openQuickSwitchView(mTasks,
-                    mNumHiddenTasks, /* updateTasks= */ true, currentFocusedIndex, onDesktop);
+            // Check if the first task is running after the recents model has updated so that we use
+            // the correct index.
+            mQuickSwitchViewController.openQuickSwitchView(
+                    mTasks,
+                    mNumHiddenTasks,
+                    /* updateTasks= */ true,
+                    currentFocusedIndex == -1 && !mControllerCallbacks.isFirstTaskRunning()
+                            ? 0 : currentFocusedIndex,
+                    onDesktop);
         });
     }
 
     private void processLoadedTasks(ArrayList<GroupTask> tasks) {
         // Only store MAX_TASK tasks, from most to least recent
         Collections.reverse(tasks);
-
-        // Hide all desktop tasks and show them on the hidden tile
-        int hiddenDesktopTasks = 0;
-        if (isDesktopModeSupported()) {
-            DesktopTask desktopTask = findDesktopTask(tasks);
-            if (desktopTask != null) {
-                hiddenDesktopTasks = desktopTask.tasks.size();
-                tasks = tasks.stream()
-                        .filter(t -> !(t instanceof DesktopTask))
-                        .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
-            }
-        }
         mTasks = tasks.stream()
                 .limit(MAX_TASKS)
                 .collect(Collectors.toList());
-        mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS) + hiddenDesktopTasks;
+        mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
     }
 
     private void processLoadedTasksOnDesktop(ArrayList<GroupTask> tasks) {
@@ -176,10 +181,14 @@
     }
 
     void closeQuickSwitchView() {
+        closeQuickSwitchView(true);
+    }
+
+    void closeQuickSwitchView(boolean animate) {
         if (mQuickSwitchViewController == null) {
             return;
         }
-        mQuickSwitchViewController.closeQuickSwitchView(true);
+        mQuickSwitchViewController.closeQuickSwitchView(animate);
     }
 
     /**
@@ -246,5 +255,20 @@
         void onCloseComplete() {
             mQuickSwitchViewController = null;
         }
+
+        boolean isTaskRunning(@Nullable GroupTask task) {
+            if (task == null) {
+                return false;
+            }
+            int runningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().taskId;
+            Task task2 = task.task2;
+
+            return runningTaskId == task.task1.key.id
+                    || (task2 != null && runningTaskId == task2.key.id);
+        }
+
+        boolean isFirstTaskRunning() {
+            return isTaskRunning(getTaskAt(0));
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index a9d50b9..48fc7d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -23,6 +23,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.ImageView;
@@ -47,6 +49,8 @@
  */
 public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
 
+    private static final float THUMBNAIL_BLUR_RADIUS = 1f;
+
     @ColorInt private final int mBorderColor;
 
     @Nullable private BorderAnimator mBorderAnimator;
@@ -89,10 +93,10 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mThumbnailView1 = findViewById(R.id.thumbnail1);
-        mThumbnailView2 = findViewById(R.id.thumbnail2);
-        mIcon1 = findViewById(R.id.icon1);
-        mIcon2 = findViewById(R.id.icon2);
+        mThumbnailView1 = findViewById(R.id.thumbnail_1);
+        mThumbnailView2 = findViewById(R.id.thumbnail_2);
+        mIcon1 = findViewById(R.id.icon_1);
+        mIcon2 = findViewById(R.id.icon_2);
         mContent = findViewById(R.id.content);
 
         Resources resources = mContext.getResources();
@@ -167,34 +171,44 @@
             @Nullable ImageView thumbnailView,
             @Nullable Task task,
             @Nullable ThumbnailUpdateFunction updateFunction) {
-        if (thumbnailView == null) {
-            return;
-        }
-        if (task == null) {
+        if (thumbnailView == null || task == null) {
             return;
         }
         if (updateFunction == null) {
-            applyThumbnail(thumbnailView, task.thumbnail);
+            applyThumbnail(thumbnailView, task.colorBackground, task.thumbnail);
             return;
         }
-        updateFunction.updateThumbnailInBackground(
-                task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData));
+        updateFunction.updateThumbnailInBackground(task, thumbnailData ->
+                applyThumbnail(thumbnailView, task.colorBackground, thumbnailData));
     }
 
     private void applyThumbnail(
-            @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) {
+            @NonNull ImageView thumbnailView,
+            @ColorInt int backgroundColor,
+            @Nullable ThumbnailData thumbnailData) {
         Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
 
-        thumbnailView.setVisibility(VISIBLE);
-        thumbnailView.setImageBitmap(bm);
+        if (thumbnailView.getVisibility() != VISIBLE) {
+            thumbnailView.setVisibility(VISIBLE);
+        }
+        thumbnailView.getBackground().setTint(bm == null ? backgroundColor : Color.TRANSPARENT);
+        thumbnailView.setImageDrawable(new BlurredBitmapDrawable(bm, THUMBNAIL_BLUR_RADIUS));
     }
 
     private void applyIcon(@Nullable ImageView iconView, @Nullable Task task) {
-        if (iconView == null || task == null) {
+        if (iconView == null || task == null || task.icon == null) {
             return;
         }
-        iconView.setVisibility(VISIBLE);
-        iconView.setImageDrawable(task.icon);
+        Drawable.ConstantState constantState = task.icon.getConstantState();
+        if (constantState == null) {
+            return;
+        }
+        if (iconView.getVisibility() != VISIBLE) {
+            iconView.setVisibility(VISIBLE);
+        }
+        // Use the bitmap directly since the drawable's scale can change
+        iconView.setImageDrawable(
+                constantState.newDrawable(getResources(), getContext().getTheme()));
     }
 
     protected interface ThumbnailUpdateFunction {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 42c423c..5d47212 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -36,11 +36,14 @@
 import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.LayoutRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.content.res.ResourcesCompat;
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.R;
@@ -48,6 +51,7 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
 
 import java.util.HashMap;
@@ -92,6 +96,7 @@
     private HorizontalScrollView mScrollView;
     private ConstraintLayout mContent;
 
+    private int mTaskViewWidth;
     private int mTaskViewHeight;
     private int mSpacing;
     private int mOutlineRadius;
@@ -128,6 +133,8 @@
         mContent = findViewById(R.id.content);
 
         Resources resources = getResources();
+        mTaskViewWidth = resources.getDimensionPixelSize(
+                R.dimen.keyboard_quick_switch_taskview_width);
         mTaskViewHeight = resources.getDimensionPixelSize(
                 R.dimen.keyboard_quick_switch_taskview_height);
         mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
@@ -135,21 +142,18 @@
         mIsRtl = Utilities.isRtl(resources);
     }
 
-    @NonNull
     private KeyboardQuickSwitchTaskView createAndAddTaskView(
             int index,
-            int width,
             boolean isFinalView,
-            boolean updateTasks,
+            @LayoutRes int resId,
             @NonNull LayoutInflater layoutInflater,
-            @Nullable View previousView,
-            @NonNull List<GroupTask> groupTasks) {
+            @Nullable View previousView) {
         KeyboardQuickSwitchTaskView taskView = (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
-                R.layout.keyboard_quick_switch_taskview, mContent, false);
+                resId, mContent, false);
         taskView.setId(View.generateViewId());
-        taskView.setOnClickListener(v -> mViewCallbacks.launchTappedTask(index));
+        taskView.setOnClickListener(v -> mViewCallbacks.launchTaskAt(index));
 
-        LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
+        LayoutParams lp = new LayoutParams(mTaskViewWidth, mTaskViewHeight);
         // Create a left-to-right ordering of views (or right-to-left in RTL locales)
         if (previousView != null) {
             lp.startToEnd = previousView.getId();
@@ -167,45 +171,11 @@
             lp.horizontalBias = 1f;
         }
 
-        GroupTask groupTask = groupTasks.get(index);
-        taskView.setThumbnails(
-                groupTask.task1,
-                groupTask.task2,
-                updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
-                updateTasks ? mViewCallbacks::updateIconInBackground : null);
-
         mContent.addView(taskView, lp);
+
         return taskView;
     }
 
-    private void createAndAddOverviewButton(
-            int width,
-            @NonNull LayoutInflater layoutInflater,
-            @Nullable View previousView,
-            @NonNull String overflowString) {
-        KeyboardQuickSwitchTaskView overviewButton =
-                (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
-                        R.layout.keyboard_quick_switch_overview, this, false);
-        overviewButton.setOnClickListener(v -> mViewCallbacks.launchTappedTask(MAX_TASKS));
-
-        overviewButton.<TextView>findViewById(R.id.text).setText(overflowString);
-
-        ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
-                width, mTaskViewHeight);
-        if (previousView == null) {
-            lp.startToStart = PARENT_ID;
-        } else {
-            lp.endToEnd = PARENT_ID;
-            lp.startToEnd = previousView.getId();
-        }
-        lp.topToTop = PARENT_ID;
-        lp.bottomToBottom = PARENT_ID;
-        lp.setMarginEnd(mSpacing);
-        lp.setMarginStart(mSpacing);
-
-        mContent.addView(overviewButton, lp);
-    }
-
     protected void applyLoadPlan(
             @NonNull Context context,
             @NonNull List<GroupTask> groupTasks,
@@ -215,32 +185,57 @@
             @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
         mViewCallbacks = viewCallbacks;
         Resources resources = context.getResources();
-        int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
-        View previousView = null;
+        Resources.Theme theme = context.getTheme();
 
+        View previousTaskView = null;
         LayoutInflater layoutInflater = LayoutInflater.from(context);
         int tasksToDisplay = Math.min(MAX_TASKS, groupTasks.size());
         for (int i = 0; i < tasksToDisplay; i++) {
-            previousView = createAndAddTaskView(
+            GroupTask groupTask = groupTasks.get(i);
+            KeyboardQuickSwitchTaskView currentTaskView = createAndAddTaskView(
                     i,
-                    width,
                     /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
-                    updateTasks,
+                    groupTask instanceof DesktopTask
+                            ? R.layout.keyboard_quick_switch_textonly_taskview
+                            : R.layout.keyboard_quick_switch_taskview,
                     layoutInflater,
-                    previousView,
-                    groupTasks);
+                    previousTaskView);
+
+            if (groupTask instanceof DesktopTask desktopTask) {
+                HashMap<String, Integer> args = new HashMap<>();
+                args.put("count", desktopTask.tasks.size());
+
+                currentTaskView.<ImageView>findViewById(R.id.icon).setImageDrawable(
+                        ResourcesCompat.getDrawable(resources, R.drawable.ic_desktop, theme));
+                currentTaskView.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+                        resources.getString(R.string.quick_switch_desktop),
+                        Locale.getDefault()).format(args));
+            } else {
+                currentTaskView.setThumbnails(
+                        groupTask.task1,
+                        groupTask.task2,
+                        updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+                        updateTasks ? mViewCallbacks::updateIconInBackground : null);
+            }
+            previousTaskView = currentTaskView;
         }
 
         if (numHiddenTasks > 0) {
             HashMap<String, Integer> args = new HashMap<>();
             args.put("count", numHiddenTasks);
-            createAndAddOverviewButton(
-                    width,
+
+            View overviewButton = createAndAddTaskView(
+                    MAX_TASKS,
+                    /* isFinalView= */ true,
+                    R.layout.keyboard_quick_switch_textonly_taskview,
                     layoutInflater,
-                    previousView,
-                    new MessageFormat(
-                            resources.getString(R.string.quick_switch_overflow),
-                            Locale.getDefault()).format(args));
+                    previousTaskView);
+
+            overviewButton.<ImageView>findViewById(R.id.icon).setImageDrawable(
+                    ResourcesCompat.getDrawable(resources, R.drawable.view_carousel, theme));
+            overviewButton.<TextView>findViewById(R.id.text).setText(new MessageFormat(
+                    resources.getString(R.string.quick_switch_overflow),
+                    Locale.getDefault()).format(args));
         }
         mDisplayingRecentTasks = !groupTasks.isEmpty();
 
@@ -362,8 +357,9 @@
                                         OPEN_OUTLINE_INTERPOLATOR));
                     }
                 });
-                animateFocusMove(-1, currentFocusIndexOverride == -1
-                        ? Math.min(mContent.getChildCount(), 1) : currentFocusIndexOverride);
+                animateFocusMove(-1, Math.min(
+                        mContent.getChildCount() - 1,
+                        currentFocusIndexOverride == -1 ? 1 : currentFocusIndexOverride));
                 displayedContent.setVisibility(VISIBLE);
                 setVisibility(VISIBLE);
                 requestFocus();
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index b29ce6b..d6ee92f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,23 +15,30 @@
  */
 package com.android.launcher3.taskbar;
 
+import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
+
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import android.animation.Animator;
+import android.app.ActivityOptions;
 import android.view.KeyEvent;
-import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.window.RemoteTransition;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.DesktopTask;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SlideInRemoteTransition;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
 import java.util.List;
@@ -76,9 +83,7 @@
             boolean updateTasks,
             int currentFocusIndexOverride,
             boolean onDesktop) {
-        TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
-        dragLayer.addView(mKeyboardQuickSwitchView);
-        dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
+        mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
         mOnDesktop = onDesktop;
 
         mKeyboardQuickSwitchView.applyLoadPlan(
@@ -90,8 +95,12 @@
                 mViewCallbacks);
     }
 
+    boolean isCloseAnimationRunning() {
+        return mCloseAnimation != null;
+    }
+
     protected void closeQuickSwitchView(boolean animate) {
-        if (mCloseAnimation != null) {
+        if (isCloseAnimationRunning()) {
             // Let currently-running animation finish.
             if (!animate) {
                 mCloseAnimation.end();
@@ -117,44 +126,59 @@
      * index will be focused.
      */
     protected int launchFocusedTask() {
-        // Launch the second-most recent task if the user quick switches too quickly, if possible.
-        return launchTaskAt(mCurrentFocusIndex == -1
-                ? (mControllerCallbacks.getTaskCount() > 1 ? 1 : 0) : mCurrentFocusIndex);
+        if (mCurrentFocusIndex != -1) {
+            return launchTaskAt(mCurrentFocusIndex);
+        }
+        // If the user quick switches too quickly, updateCurrentFocusIndex might not have run.
+        return launchTaskAt(mControllerCallbacks.isFirstTaskRunning()
+                && mControllerCallbacks.getTaskCount() > 1 ? 1 : 0);
     }
 
     private int launchTaskAt(int index) {
-        if (mCloseAnimation != null) {
+        if (isCloseAnimationRunning()) {
             // Ignore taps on task views and alt key unpresses while the close animation is running.
             return -1;
         }
         // Even with a valid index, this can be null if the user tries to quick switch before the
         // views have been added in the KeyboardQuickSwitchView.
-        View taskView = mKeyboardQuickSwitchView.getTaskAt(index);
         GroupTask task = mControllerCallbacks.getTaskAt(index);
         if (task == null) {
-            return Math.max(0, index);
+            return mOnDesktop ? 1 : Math.max(0, index);
         }
-        Task task2 = task.task2;
-        int runningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().taskId;
-        if (runningTaskId == task.task1.key.id
-                || (task2 != null && runningTaskId == task2.key.id)) {
+        if (mControllerCallbacks.isTaskRunning(task)) {
             // Ignore attempts to run the selected task if it is already running.
             return -1;
         }
 
-        if (mOnDesktop) {
+        TaskbarActivityContext context = mControllers.taskbarActivityContext;
+        RemoteTransition remoteTransition = new RemoteTransition(new SlideInRemoteTransition(
+                Utilities.isRtl(mControllers.taskbarActivityContext.getResources()),
+                context.getDeviceProfile().overviewPageSpacing,
+                QuickStepContract.getWindowCornerRadius(context),
+                AnimationUtils.loadInterpolator(
+                        context, android.R.interpolator.fast_out_extra_slow_in)),
+                "SlideInTransition");
+        if (task instanceof DesktopTask) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
+                            .showDesktopApps(
+                                    mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
+                                    remoteTransition));
+        } else if (mOnDesktop) {
             UI_HELPER_EXECUTOR.execute(() ->
                     SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
                             .showDesktopApp(task.task1.key.id));
-        } else if (task2 == null) {
-            UI_HELPER_EXECUTOR.execute(() ->
-                    ActivityManagerWrapper.getInstance().startActivityFromRecents(
-                            task.task1.key,
-                            mControllers.taskbarActivityContext.getActivityLaunchOptions(
-                                    taskView == null ? mKeyboardQuickSwitchView : taskView, null)
-                                    .options));
+        } else if (task.task2 == null) {
+            UI_HELPER_EXECUTOR.execute(() -> {
+                ActivityOptions activityOptions = mControllers.taskbarActivityContext
+                        .makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED).options;
+                activityOptions.setRemoteTransition(remoteTransition);
+
+                ActivityManagerWrapper.getInstance().startActivityFromRecents(
+                        task.task1.key, activityOptions);
+            });
         } else {
-            mControllers.uiController.launchSplitTasks(task);
+            mControllers.uiController.launchSplitTasks(task, remoteTransition);
         }
         return -1;
     }
@@ -173,7 +197,7 @@
         pw.println(prefix + "KeyboardQuickSwitchViewController:");
 
         pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
-        pw.println(prefix + "\tcloseAnimationRunning=" + (mCloseAnimation != null));
+        pw.println(prefix + "\tisCloseAnimationRunning=" + isCloseAnimationRunning());
         pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
     }
 
@@ -184,13 +208,18 @@
                     && keyCode != KeyEvent.KEYCODE_DPAD_RIGHT
                     && keyCode != KeyEvent.KEYCODE_DPAD_LEFT
                     && keyCode != KeyEvent.KEYCODE_GRAVE
-                    && keyCode != KeyEvent.KEYCODE_ESCAPE) {
+                    && keyCode != KeyEvent.KEYCODE_ESCAPE
+                    && keyCode != KeyEvent.KEYCODE_ENTER) {
                 return false;
             }
             if (keyCode == KeyEvent.KEYCODE_GRAVE || keyCode == KeyEvent.KEYCODE_ESCAPE) {
                 closeQuickSwitchView(true);
                 return true;
             }
+            if (keyCode == KeyEvent.KEYCODE_ENTER) {
+                launchTaskAt(mCurrentFocusIndex);
+                return true;
+            }
             if (!allowTraversal) {
                 return false;
             }
@@ -220,9 +249,9 @@
             mCurrentFocusIndex = index;
         }
 
-        void launchTappedTask(int index) {
-            KeyboardQuickSwitchViewController.this.launchTaskAt(index);
-            closeQuickSwitchView(true);
+        void launchTaskAt(int index) {
+            mCurrentFocusIndex = index;
+            mControllers.taskbarActivityContext.launchKeyboardFocusedTask();
         }
 
         void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 159a6ef..489102f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,10 +16,12 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
+import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
 import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
 import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -27,11 +29,13 @@
 import android.util.Log;
 import android.view.TaskTransitionSpec;
 import android.view.WindowManagerGlobal;
+import android.window.RemoteTransition;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
@@ -40,13 +44,18 @@
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.taskbar.bubbles.BubbleBarController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.OnboardingPrefs;
+import com.android.quickstep.HomeVisibilityState;
+import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
 
 import java.io.PrintWriter;
@@ -73,6 +82,7 @@
                     AnimatedFloat.VALUE, DISPLAY_PROGRESS_COUNT, Float::max);
 
     private final QuickstepLauncher mLauncher;
+    private final HomeVisibilityState mHomeState;
 
     private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
             dp -> {
@@ -81,6 +91,8 @@
                     mControllers.taskbarViewController.onRotationChanged(dp);
                 }
             };
+    private final HomeVisibilityState.VisibilityChangeListener  mVisibilityChangeListener =
+            this::onLauncherVisibilityChanged;
 
     // Initialized in init.
     private final TaskbarLauncherStateController
@@ -88,6 +100,7 @@
 
     public LauncherTaskbarUIController(QuickstepLauncher launcher) {
         mLauncher = launcher;
+        mHomeState =  SystemUiProxy.INSTANCE.get(mLauncher).getHomeVisibilityState();
     }
 
     @Override
@@ -98,8 +111,11 @@
                 mControllers.getSharedState().sysuiStateFlags);
 
         mLauncher.setTaskbarUIController(this);
-
-        onLauncherVisibilityChanged(mLauncher.hasBeenResumed(), true /* fromInit */);
+        mHomeState.addListener(mVisibilityChangeListener);
+        onLauncherVisibilityChanged(
+                Flags.useActivityOverlay()
+                        ? mHomeState.isHomeVisible() : mLauncher.hasBeenResumed(),
+                true /* fromInit */);
 
         onStashedInAppChanged(mLauncher.getDeviceProfile());
         mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
@@ -123,6 +139,7 @@
 
         mLauncher.setTaskbarUIController(null);
         mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+        mHomeState.removeListener(mVisibilityChangeListener);
         updateTaskTransitionSpec(true);
     }
 
@@ -171,6 +188,7 @@
     /**
      * Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
      */
+    @Override
     public void onLauncherVisibilityChanged(boolean isVisible) {
         onLauncherVisibilityChanged(isVisible, false /* fromInit */);
     }
@@ -184,7 +202,7 @@
                         ? TRANSIENT_TASKBAR_TRANSITION_DURATION
                         : (!isVisible
                                 ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
-                                : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION));
+                                : QuickstepTransitionManager.getTaskbarToHomeDuration()));
     }
 
     @Nullable
@@ -199,8 +217,20 @@
             return null;
         }
 
+        DesktopVisibilityController desktopController =
+                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+        if (!enableDesktopWindowingWallpaperActivity()
+                && desktopController != null
+                && desktopController.areDesktopTasksVisible()) {
+            // TODO: b/333533253 - Remove after flag rollout
+            isVisible = false;
+        }
+
         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
-        return mTaskbarLauncherStateController.applyState(fromInit ? 0 : duration, startAnimation);
+        if (fromInit) {
+            duration = 0;
+        }
+        return mTaskbarLauncherStateController.applyState(duration, startAnimation);
     }
 
     @Override
@@ -210,7 +240,8 @@
 
     @Override
     public void refreshResumedState() {
-        onLauncherVisibilityChanged(mLauncher.hasBeenResumed());
+        onLauncherVisibilityChanged(Flags.useActivityOverlay()
+                ? mHomeState.isHomeVisible() : mLauncher.hasBeenResumed());
     }
 
     @Override
@@ -231,6 +262,11 @@
         return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
     }
 
+    public void updateTaskbarLauncherStateGoingHome() {
+        mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, true);
+        mTaskbarLauncherStateController.applyState();
+    }
+
     public boolean isDraggingItem() {
         return mControllers.taskbarDragController.isDragging();
     }
@@ -270,6 +306,8 @@
      */
     public void showEduOnAppLaunch() {
         if (!shouldShowEduOnAppLaunch()) {
+            // Called in case the edu finishes and circle to search edu is still pending
+            mControllers.taskbarEduTooltipController.maybeShowCircleToSearchEdu();
             return;
         }
 
@@ -283,6 +321,11 @@
         mControllers.taskbarEduTooltipController.maybeShowSwipeEdu();
     }
 
+    /** Will make the next onRecentsAnimationFinished() animation a no-op. */
+    public void setSkipNextRecentsAnimEnd() {
+        mTaskbarLauncherStateController.setSkipNextRecentsAnimEnd();
+    }
+
     /**
      * Returns {@code true} if a Taskbar education should be shown on application launch.
      */
@@ -380,8 +423,15 @@
     }
 
     @Override
-    protected boolean isInOverview() {
-        return mTaskbarLauncherStateController.isInOverview();
+    protected boolean isInOverviewUi() {
+        return mTaskbarLauncherStateController.isInOverviewUi();
+    }
+
+    @Override
+    protected boolean canToggleHomeAllApps() {
+        return mLauncher.isResumed()
+                && !mTaskbarLauncherStateController.isInOverviewUi()
+                && !mLauncher.areDesktopTasksVisible();
     }
 
     @Override
@@ -390,8 +440,9 @@
     }
 
     @Override
-    public void launchSplitTasks(@NonNull GroupTask groupTask) {
-        mLauncher.launchSplitTasks(groupTask);
+    public void launchSplitTasks(
+            @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
+        mLauncher.launchSplitTasks(groupTask, remoteTransition);
     }
 
     @Override
@@ -399,6 +450,12 @@
         mTaskbarLauncherStateController.resetIconAlignment();
     }
 
+    @Nullable
+    @Override
+    protected TISBindHelper getTISBindHelper() {
+        return mLauncher.getTISBindHelper();
+    }
+
     @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
         super.dumpLogs(prefix, pw);
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index bed4c37..2c5aeb3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -25,13 +25,12 @@
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
-import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
-import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_BACK;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
+import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_SPACE;
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_SMALL_SCREEN;
 import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
@@ -63,6 +62,7 @@
 import android.graphics.Region;
 import android.graphics.Region.Op;
 import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.PaintDrawable;
 import android.graphics.drawable.RotateDrawable;
 import android.inputmethodservice.InputMethodService;
@@ -80,6 +80,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.Space;
 
 import androidx.annotation.Nullable;
 
@@ -92,12 +93,14 @@
 import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
 import com.android.launcher3.util.DimensionUtils;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.systemui.shared.navigationbar.KeyButtonRipple;
 import com.android.systemui.shared.rotation.FloatingRotationButton;
 import com.android.systemui.shared.rotation.RotationButton;
 import com.android.systemui.shared.rotation.RotationButtonController;
@@ -139,6 +142,9 @@
 
     private static final String NAV_BUTTONS_SEPARATE_WINDOW_TITLE = "Taskbar Nav Buttons";
 
+    private static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
+    private static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
+
     public static final int ALPHA_INDEX_IMMERSIVE_MODE = 0;
     public static final int ALPHA_INDEX_KEYGUARD_OR_DISABLE = 1;
     public static final int ALPHA_INDEX_SUW = 2;
@@ -151,7 +157,7 @@
     private final TaskbarActivityContext mContext;
     private final @Nullable Context mNavigationBarPanelContext;
     private final WindowManagerProxy mWindowManagerProxy;
-    private final FrameLayout mNavButtonsView;
+    private final NearestTouchFrame mNavButtonsView;
     private final LinearLayout mNavButtonContainer;
     // Used for IME+A11Y buttons
     private final ViewGroup mEndContextualContainer;
@@ -206,9 +212,10 @@
             this::onComputeInsetsForSeparateWindow;
     private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
     private ImageView mRecentsButton;
+    private Space mSpace;
 
     public NavbarButtonsViewController(TaskbarActivityContext context,
-            @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
+            @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
         mContext = context;
         mNavigationBarPanelContext = navigationBarPanelContext;
         mWindowManagerProxy = WindowManagerProxy.INSTANCE.get(mContext);
@@ -237,9 +244,9 @@
         DeviceProfile deviceProfile = mContext.getDeviceProfile();
         Resources resources = mContext.getResources();
         Point p = !mContext.isUserSetupComplete()
-                ? new Point(0, mControllers.taskbarActivityContext.getSetupWindowHeight())
+                ? new Point(0, mControllers.taskbarActivityContext.getSetupWindowSize())
                 : DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
-                        TaskbarManager.isPhoneMode(deviceProfile));
+                        mContext.isPhoneMode());
         mNavButtonsView.getLayoutParams().height = p.y;
 
         mIsImeRenderingNavButtons =
@@ -305,7 +312,7 @@
             initButtons(mNavButtonContainer, mEndContextualContainer,
                     mControllers.navButtonController);
             updateButtonLayoutSpacing();
-            updateStateForFlag(FLAG_SMALL_SCREEN, isPhoneButtonNavMode(mContext));
+            updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneButtonNavMode());
 
             mPropertyHolders.add(new StatePropertyHolder(
                     mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
@@ -388,7 +395,7 @@
         int navButtonSize = mContext.getResources().getDimensionPixelSize(
                 R.dimen.taskbar_nav_buttons_size);
         boolean isRtl = Utilities.isRtl(mContext.getResources());
-        if (!isPhoneMode(mContext.getDeviceProfile())) {
+        if (!mContext.isPhoneMode()) {
             mPropertyHolders.add(new StatePropertyHolder(
                     mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
                             || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
@@ -431,6 +438,11 @@
         mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
                 flags -> (flags & FLAG_A11Y_VISIBLE) != 0
                         && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
+
+        mSpace = new Space(mNavButtonsView.getContext());
+        mSpace.setOnClickListener(view -> navButtonController.onButtonClick(BUTTON_SPACE, view));
+        mSpace.setOnLongClickListener(view ->
+                navButtonController.onButtonLongClick(BUTTON_SPACE, view));
     }
 
     private void parseSystemUiFlags(int sysUiStateFlags) {
@@ -517,6 +529,10 @@
         return (mState & FLAG_IME_VISIBLE) != 0;
     }
 
+    public boolean isImeRenderingNavButtons() {
+        return mIsImeRenderingNavButtons;
+    }
+
     /**
      * Returns true if the home button is disabled
      */
@@ -632,7 +648,7 @@
      * Sets the translationY of the nav buttons based on the current device state.
      */
     public void updateNavButtonTranslationY() {
-        if (isPhoneButtonNavMode(mContext)) {
+        if (mContext.isPhoneButtonNavMode()) {
             return;
         }
         final float normalTranslationY = mTaskbarNavButtonTranslationY.value;
@@ -667,6 +683,11 @@
 
         for (ImageView button : mAllButtons) {
             button.setImageTintList(ColorStateList.valueOf(iconColor));
+            Drawable background = button.getBackground();
+            if (background instanceof KeyButtonRipple) {
+                ((KeyButtonRipple) background).setDarkIntensity(
+                        mTaskbarNavButtonDarkIntensity.value);
+            }
         }
     }
 
@@ -717,18 +738,39 @@
         // end-aligned, so start-align instead.
         FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
                 mNavButtonContainer.getLayoutParams();
+        FrameLayout.LayoutParams navButtonsViewLayoutParams = (FrameLayout.LayoutParams)
+                mNavButtonsView.getLayoutParams();
         Resources resources = mContext.getResources();
         DeviceProfile deviceProfile = mContext.getDeviceProfile();
-        int setupMargin = resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_margin);
-        navButtonsLayoutParams.setMarginStart(setupMargin);
-        navButtonsLayoutParams.bottomMargin = !deviceProfile.isLandscape
-                ? 0
-                : setupMargin -
-                        (resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2);
+
         navButtonsLayoutParams.setMarginEnd(0);
         navButtonsLayoutParams.gravity = Gravity.START;
-        mNavButtonsView.getLayoutParams().height =
-                mControllers.taskbarActivityContext.getSetupWindowHeight();
+        mControllers.taskbarActivityContext.setTaskbarWindowSize(
+                mControllers.taskbarActivityContext.getSetupWindowSize());
+
+        // If SUW is on a large screen device that is landscape (or has a square aspect
+        // ratio) the back button has to be placed accordingly
+        if ((deviceProfile.isTablet && deviceProfile.isLandscape)
+                || (deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
+                && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND)) {
+            navButtonsLayoutParams.setMarginStart(
+                    resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_start_margin));
+            navButtonsViewLayoutParams.bottomMargin = resources.getDimensionPixelSize(
+                    R.dimen.taskbar_back_button_suw_bottom_margin);
+            navButtonsLayoutParams.height = resources.getDimensionPixelSize(
+                    R.dimen.taskbar_back_button_suw_height);
+        } else {
+            int phoneOrPortraitSetupMargin = resources.getDimensionPixelSize(
+                    R.dimen.taskbar_contextual_button_suw_margin);
+            navButtonsLayoutParams.setMarginStart(phoneOrPortraitSetupMargin);
+            navButtonsLayoutParams.bottomMargin = !deviceProfile.isLandscape
+                    ? 0
+                    : phoneOrPortraitSetupMargin - (resources.getDimensionPixelSize(
+                            R.dimen.taskbar_nav_buttons_size) / 2);
+            navButtonsViewLayoutParams.height = resources.getDimensionPixelSize(
+                    R.dimen.taskbar_contextual_button_suw_height);
+        }
+        mNavButtonsView.setLayoutParams(navButtonsViewLayoutParams);
         mNavButtonContainer.setLayoutParams(navButtonsLayoutParams);
     }
 
@@ -750,10 +792,10 @@
                     NavButtonLayoutFactory.Companion.getUiLayoutter(
                             dp, mNavButtonsView, mImeSwitcherButton,
                             mControllers.rotationButtonController.getRotationButton(),
-                            mA11yButton, res, isInKidsMode, isInSetup, isThreeButtonNav,
-                            TaskbarManager.isPhoneMode(dp),
-                            mWindowManagerProxy.getRotation(mContext));
-            navButtonLayoutter.layoutButtons(dp, isA11yButtonPersistent());
+                            mA11yButton, mSpace, res, isInKidsMode, isInSetup, isThreeButtonNav,
+                            mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
+            navButtonLayoutter.layoutButtons(mContext, isA11yButtonPersistent());
+            updateButtonsBackground();
             updateNavButtonColor();
             return;
         }
@@ -762,9 +804,11 @@
             handleSetupUi();
 
             // Hide back button in SUW if keyboard is showing (IME draws its own back).
-            mPropertyHolders.add(new StatePropertyHolder(
-                    mBackButtonAlpha.get(ALPHA_INDEX_SUW),
-                    flags -> (flags & FLAG_IME_VISIBLE) == 0));
+            if (mIsImeRenderingNavButtons) {
+                mPropertyHolders.add(new StatePropertyHolder(
+                        mBackButtonAlpha.get(ALPHA_INDEX_SUW),
+                        flags -> (flags & FLAG_IME_VISIBLE) == 0));
+            }
         } else if (isInKidsMode) {
             int iconSize = res.getDimensionPixelSize(
                     R.dimen.taskbar_icon_size_kids);
@@ -873,7 +917,27 @@
                 }
             }
         }
+    }
 
+    private void updateButtonsBackground() {
+        boolean clipped = !mContext.isPhoneButtonNavMode();
+        mNavButtonContainer.setClipToPadding(clipped);
+        mNavButtonContainer.setClipChildren(clipped);
+        mNavButtonsView.setClipToPadding(clipped);
+        mNavButtonsView.setClipChildren(clipped);
+
+        for (ImageView button : mAllButtons) {
+            updateButtonBackground(button, mContext.isPhoneButtonNavMode());
+        }
+    }
+
+    private static void updateButtonBackground(View view, boolean isPhoneButtonNavMode) {
+        if (isPhoneButtonNavMode) {
+            view.setBackground(new KeyButtonRipple(view.getContext(), view,
+                    R.dimen.key_button_ripple_max_width));
+        } else {
+            view.setBackgroundResource(R.drawable.taskbar_icon_click_feedback_roundrect);
+        }
     }
 
     public void onDestroy() {
@@ -978,6 +1042,8 @@
                 + mOnTaskbarBackgroundNavButtonColorOverride.value);
         pw.println(prefix + "\t\tmOnBackgroundNavButtonColorOverrideMultiplier="
                 + mOnBackgroundNavButtonColorOverrideMultiplier.value);
+
+        mNavButtonsView.dumpLogs(prefix + "\t", pw);
     }
 
     private static String getStateString(int flags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index da1f766..f258b47 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -15,11 +15,14 @@
  */
 package com.android.launcher3.taskbar;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
+import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Outline;
@@ -37,6 +40,7 @@
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.NavHandle;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 
 import java.io.PrintWriter;
@@ -44,7 +48,8 @@
 /**
  * Handles properties/data collection, then passes the results to our stashed handle View to render.
  */
-public class StashedHandleViewController implements TaskbarControllers.LoggableTaskbarController {
+public class StashedHandleViewController implements TaskbarControllers.LoggableTaskbarController,
+        NavHandle {
 
     public static final int ALPHA_INDEX_STASHED = 0;
     public static final int ALPHA_INDEX_HOME_DISABLED = 1;
@@ -83,6 +88,7 @@
 
     // States that affect whether region sampling is enabled or not
     private boolean mIsStashed;
+    private boolean mIsLumaSamplingEnabled;
     private boolean mTaskbarHidden;
 
     private float mTranslationYForSwipe;
@@ -107,7 +113,7 @@
         mControllers = controllers;
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         Resources resources = mActivity.getResources();
-        if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) {
+        if (mActivity.isPhoneGestureNavMode()) {
             mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_phone_size);
             mStashedHandleWidth =
                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
@@ -120,7 +126,7 @@
         mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin;
 
         mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue(
-                isPhoneGestureNavMode(deviceProfile) ? 1 : 0);
+                mActivity.isPhoneGestureNavMode() ? 1 : 0);
         mTaskbarStashedHandleHintScale.updateValue(1f);
 
         final int stashedTaskbarHeight = mControllers.taskbarStashController.getStashedHeight();
@@ -148,7 +154,7 @@
             view.setPivotY(stashedCenterY);
         });
         initRegionSampler();
-        if (isPhoneGestureNavMode(deviceProfile)) {
+        if (mActivity.isPhoneGestureNavMode()) {
             onIsStashedChanged(true);
         }
     }
@@ -184,10 +190,6 @@
         mRegionSamplingHelper = null;
     }
 
-    private boolean isPhoneGestureNavMode(DeviceProfile deviceProfile) {
-        return TaskbarManager.isPhoneMode(deviceProfile) && !mActivity.isThreeButtonNav();
-    }
-
     public MultiPropertyFactory<View> getStashedHandleAlpha() {
         return mTaskbarStashedHandleAlpha;
     }
@@ -238,8 +240,21 @@
     /** Called when taskbar is stashed or unstashed. */
     public void onIsStashedChanged(boolean isStashed) {
         mIsStashed = isStashed;
+        updateSamplingState();
+    }
+
+    public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+        if (DEFAULT_DISPLAY != displayId) {
+            return;
+        }
+
+        mIsLumaSamplingEnabled = enable;
+        updateSamplingState();
+    }
+
+    private void updateSamplingState() {
         updateRegionSamplingWindowVisibility();
-        if (isStashed) {
+        if (shouldSample()) {
             mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
             mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
         } else {
@@ -247,6 +262,10 @@
         }
     }
 
+    private boolean shouldSample() {
+        return mIsStashed && mIsLumaSamplingEnabled;
+    }
+
     protected void updateStashedHandleHintScale() {
         mStashedHandleView.setScaleX(mTaskbarStashedHandleHintScale.value);
         mStashedHandleView.setScaleY(mTaskbarStashedHandleHintScale.value);
@@ -286,7 +305,7 @@
     }
 
     private void updateRegionSamplingWindowVisibility() {
-        mRegionSamplingHelper.setWindowVisible(mIsStashed && !mTaskbarHidden);
+        mRegionSamplingHelper.setWindowVisible(shouldSample() && !mTaskbarHidden);
     }
 
     public boolean isStashedHandleVisible() {
@@ -302,4 +321,24 @@
         pw.println(prefix + "\tmStashedHandleHeight=" + mStashedHandleHeight);
         mRegionSamplingHelper.dump(prefix, pw);
     }
+
+    @Override
+    public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {
+        // TODO(b/308693847): Animate similarly to NavigationHandle.java (SysUI).
+    }
+
+    @Override
+    public boolean isNavHandleStashedTaskbar() {
+        return true;
+    }
+
+    @Override
+    public boolean canNavHandleBeLongPressed() {
+        return isStashedHandleVisible();
+    }
+
+    @Override
+    public int getNavHandleWidth(Context context) {
+        return mStashedHandleWidth;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 4290948..679528b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -17,6 +17,7 @@
 
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.os.Trace.TRACE_TAG_APP;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -37,8 +38,11 @@
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
 import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
 
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
@@ -49,10 +53,10 @@
 import android.content.pm.ActivityInfo.Config;
 import android.content.pm.LauncherApps;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
+import android.os.IRemoteCallback;
 import android.os.Process;
 import android.os.Trace;
 import android.provider.Settings;
@@ -64,12 +68,13 @@
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.graphics.Insets;
+import androidx.core.view.WindowInsetsCompat;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BubbleTextView;
@@ -86,6 +91,7 @@
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -95,6 +101,7 @@
 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
 import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
 import com.android.launcher3.taskbar.bubbles.BubbleBarView;
 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
@@ -102,12 +109,14 @@
 import com.android.launcher3.taskbar.bubbles.BubbleDragController;
 import com.android.launcher3.taskbar.bubbles.BubbleStashController;
 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
 import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
@@ -120,6 +129,9 @@
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.NavHandle;
+import com.android.quickstep.RecentsModel;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
@@ -158,7 +170,7 @@
     private WindowManager.LayoutParams mWindowLayoutParams;
     private boolean mIsFullscreen;
     // The size we should return to when we call setTaskbarWindowFullscreen(false)
-    private int mLastRequestedNonFullscreenHeight;
+    private int mLastRequestedNonFullscreenSize;
 
     private NavigationMode mNavMode;
     private boolean mImeDrawsImeNavBar;
@@ -214,7 +226,7 @@
         Context c = getApplicationContext();
         mWindowManager = c.getSystemService(WindowManager.class);
 
-        boolean phoneMode = TaskbarManager.isPhoneMode(mDeviceProfile);
+        boolean phoneMode = isPhoneMode();
         mLeftCorner = phoneMode
                 ? null
                 : display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
@@ -229,14 +241,14 @@
         mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
-        FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
+        NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
         StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
         BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
         StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
 
         mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
 
-        final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
+        final boolean isPcMode = getPackageManager().hasSystemFeature(FEATURE_PC);
 
         // If Bubble bar is present, TaskbarControllers depends on it so build it first.
         Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
@@ -248,7 +260,10 @@
                     new BubbleStashController(this),
                     new BubbleStashedHandleViewController(this, bubbleHandleView),
                     new BubbleDragController(this),
-                    new BubbleDismissController(this, mDragLayer)));
+                    new BubbleDismissController(this, mDragLayer),
+                    new BubbleBarPinController(this, mDragLayer,
+                            () -> getDeviceProfile().getDisplayInfo().currentSize)
+            ));
         }
 
         // Construct controllers.
@@ -265,7 +280,7 @@
         mControllers = new TaskbarControllers(this,
                 new TaskbarDragController(this),
                 buttonController,
-                isDesktopMode
+                isPcMode
                         ? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
                                 navButtonsView)
                         : new NavbarButtonsViewController(this, mNavigationBarPanelContext,
@@ -290,9 +305,7 @@
                 new VoiceInteractionWindowController(this),
                 new TaskbarTranslationController(this),
                 new TaskbarSpringOnStashController(this),
-                isDesktopMode
-                        ? new DesktopTaskbarRecentAppsController(this)
-                        : TaskbarRecentAppsController.DEFAULT,
+                createTaskbarRecentAppsController(isPcMode),
                 new TaskbarEduTooltipController(this),
                 new KeyboardQuickSwitchController(),
                 new TaskbarPinningController(this),
@@ -301,6 +314,18 @@
         mLauncherPrefs = LauncherPrefs.get(this);
     }
 
+    private TaskbarRecentAppsController createTaskbarRecentAppsController(boolean isPcMode) {
+        if (isPcMode) return new DesktopTaskbarRecentAppsController(this);
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        final boolean showRunningAppsInDesktopMode = enableDesktopWindowingMode()
+                && enableDesktopWindowingTaskbarRunningApps();
+        return showRunningAppsInDesktopMode
+                        ? new DesktopTaskbarRunningAppsController(
+                                RecentsModel.INSTANCE.get(this),
+                                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController())
+                        : TaskbarRecentAppsController.DEFAULT;
+    }
+
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
     public void updateDeviceProfile(DeviceProfile launcherDp) {
         applyDeviceProfile(launcherDp);
@@ -326,7 +351,7 @@
 
             // Update icon size
             deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
-            deviceProfile.updateIconSize(1f, getResources());
+            deviceProfile.updateIconSize(1f, this);
         };
         mDeviceProfile = originDeviceProfile.toBuilder(this)
                 .withDimensionsOverride(overrideProvider).build();
@@ -357,7 +382,7 @@
 
     public void init(@NonNull TaskbarSharedState sharedState) {
         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
-        mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
+        mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
         mWindowLayoutParams = createAllWindowParams();
 
         // Initialize controllers after all are constructed.
@@ -371,6 +396,8 @@
         onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
                 sharedState.systemBarAttrsBehavior);
         onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
+        onNavigationBarLumaSamplingEnabled(sharedState.mLumaSamplingDisplayId,
+                sharedState.mIsLumaSamplingEnabled);
 
         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
             // W/ the flag not set this entire class gets re-created, which resets the value of
@@ -388,6 +415,50 @@
     }
 
     /**
+     * @return {@code true} if the device profile isn't a large screen profile and we are using a
+     * single window for taskbar and navbar.
+     */
+    public boolean isPhoneMode() {
+        return ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone;
+    }
+
+    /**
+     * @return {@code true} if {@link #isPhoneMode()} is true and we're using 3 button-nav
+     */
+    public boolean isPhoneButtonNavMode() {
+        return isPhoneMode() && isThreeButtonNav();
+    }
+
+    /**
+     * @return {@code true} if {@link #isPhoneMode()} is true and we're using gesture nav
+     */
+    public boolean isPhoneGestureNavMode() {
+        return isPhoneMode() && !isThreeButtonNav();
+    }
+
+    /**
+     * Returns if software keyboard is docked or input toolbar is placed at the taskbar area
+     */
+    public boolean isImeDocked() {
+        View dragLayer = getDragLayer();
+        WindowInsets insets = dragLayer.getRootWindowInsets();
+        if (insets == null) {
+            return false;
+        }
+
+        WindowInsetsCompat insetsCompat =
+                WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer.getRootView());
+
+        if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
+            Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
+            return imeInsets.bottom >= getResources().getDimensionPixelSize(
+                    R.dimen.floating_ime_inset_height);
+        } else {
+            return false;
+        }
+    }
+
+    /**
      * Show Taskbar upon receiving broadcast
      */
     public void showTaskbarFromBroadcast() {
@@ -428,6 +499,10 @@
         return mTransientTaskbarBounds;
     }
 
+    protected float getCurrentTaskbarWidth() {
+        return mControllers.taskbarViewController.getCurrentVisualTaskbarWidth();
+    }
+
     @Override
     public StatsLogManager getStatsLogManager() {
         // Used to mock, can't mock a default interface method directly
@@ -450,7 +525,7 @@
         }
         WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
                 MATCH_PARENT,
-                mLastRequestedNonFullscreenHeight,
+                mLastRequestedNonFullscreenSize,
                 type,
                 windowFlags,
                 PixelFormat.TRANSLUCENT);
@@ -464,62 +539,33 @@
         windowLayoutParams.privateFlags =
                 WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
         windowLayoutParams.accessibilityTitle = getString(
-                TaskbarManager.isPhoneMode(mDeviceProfile)
-                        ? R.string.taskbar_phone_a11y_title
-                        : R.string.taskbar_a11y_title);
+                isPhoneMode() ? R.string.taskbar_phone_a11y_title : R.string.taskbar_a11y_title);
 
         return windowLayoutParams;
     }
 
     /**
      * Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
-     * for taskbar showing as navigation bar
+     * for taskbar
      */
     private WindowManager.LayoutParams createAllWindowParams() {
         final int windowType =
                 ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
         WindowManager.LayoutParams windowLayoutParams =
                 createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
-        boolean isPhoneNavMode = TaskbarManager.isPhoneButtonNavMode(this);
-        if (!isPhoneNavMode) {
-            return windowLayoutParams;
-        }
 
-        // Provide WM layout params for all rotations to cache, see NavigationBar#getBarLayoutParams
-        int width = WindowManager.LayoutParams.MATCH_PARENT;
-        int height = WindowManager.LayoutParams.MATCH_PARENT;
-        int gravity = Gravity.BOTTOM;
         windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
         for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
             WindowManager.LayoutParams lp =
                     createDefaultWindowLayoutParams(windowType,
                             TaskbarActivityContext.WINDOW_TITLE);
-            switch (rot) {
-                case Surface.ROTATION_0, Surface.ROTATION_180 -> {
-                    // Defaults are fine
-                    width = WindowManager.LayoutParams.MATCH_PARENT;
-                    height = mLastRequestedNonFullscreenHeight;
-                    gravity = Gravity.BOTTOM;
-                }
-                case Surface.ROTATION_90 -> {
-                    width = mLastRequestedNonFullscreenHeight;
-                    height = WindowManager.LayoutParams.MATCH_PARENT;
-                    gravity = Gravity.END;
-                }
-                case Surface.ROTATION_270 -> {
-                    width = mLastRequestedNonFullscreenHeight;
-                    height = WindowManager.LayoutParams.MATCH_PARENT;
-                    gravity = Gravity.START;
-                }
-
+            if (isPhoneButtonNavMode()) {
+                populatePhoneButtonNavModeWindowLayoutParams(rot, lp);
             }
-            lp.width = width;
-            lp.height = height;
-            lp.gravity = gravity;
             windowLayoutParams.paramsForRotation[rot] = lp;
         }
 
-        // Override current layout params
+        // Override with current layout params
         WindowManager.LayoutParams currentParams =
                 windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
         windowLayoutParams.width = currentParams.width;
@@ -529,10 +575,36 @@
         return windowLayoutParams;
     }
 
+    /**
+     * Update {@link WindowManager.LayoutParams} with values specific to phone and 3 button
+     * navigation users
+     */
+    private void populatePhoneButtonNavModeWindowLayoutParams(int rot,
+            WindowManager.LayoutParams lp) {
+        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+        lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+        lp.gravity = Gravity.BOTTOM;
+
+        // Override with per-rotation specific values
+        switch (rot) {
+            case Surface.ROTATION_0, Surface.ROTATION_180 -> {
+                lp.height = mLastRequestedNonFullscreenSize;
+            }
+            case Surface.ROTATION_90 -> {
+                lp.width = mLastRequestedNonFullscreenSize;
+                lp.gravity = Gravity.END;
+            }
+            case Surface.ROTATION_270 -> {
+                lp.width = mLastRequestedNonFullscreenSize;
+                lp.gravity = Gravity.START;
+            }
+        }
+    }
+
     public void onConfigurationChanged(@Config int configChanges) {
         mControllers.onConfigurationChanged(configChanges);
         if (!mIsUserSetupComplete) {
-            setTaskbarWindowHeight(getSetupWindowHeight());
+            setTaskbarWindowSize(getSetupWindowSize());
         }
     }
 
@@ -580,6 +652,11 @@
         return mControllers.bubbleControllers.orElse(null);
     }
 
+    @NonNull
+    public NavHandle getNavHandle() {
+        return mControllers.stashedHandleViewController;
+    }
+
     @Override
     public ViewCache getViewCache() {
         return mViewCache;
@@ -602,7 +679,7 @@
 
         LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
                 LauncherAtom.TaskBarContainer.newBuilder();
-        if (mControllers.uiController.isInOverview()) {
+        if (mControllers.uiController.isInOverviewUi()) {
             taskbarBuilder.setTaskSwitcherContainer(
                     LauncherAtom.TaskSwitcherContainer.newBuilder());
         }
@@ -706,13 +783,14 @@
     @Override
     public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
         RunnableList callbacks = new RunnableList();
-        ActivityOptions options = ActivityOptions.makeCustomAnimation(
-                this, 0, 0, Color.TRANSPARENT,
-                Executors.MAIN_EXECUTOR.getHandler(), null,
-                elapsedRealTime -> callbacks.executeAllAndDestroy());
+        ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
         options.setSplashScreenStyle(splashScreenStyle);
         options.setPendingIntentBackgroundActivityStartMode(
                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+        IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
+        options.setOnAnimationAbortListener(endCallback);
+        options.setOnAnimationFinishedListener(endCallback);
+
         return new ActivityOptionsWrapper(options, callbacks);
     }
 
@@ -816,6 +894,11 @@
                 .updateValue(darkIntensity);
     }
 
+    public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+        mControllers.stashedHandleViewController.onNavigationBarLumaSamplingEnabled(displayId,
+                enable);
+    }
+
     /**
      * Called to update a {@link AutohideSuspendFlag} with a new value.
      */
@@ -829,7 +912,7 @@
     public void setTaskbarWindowFullscreen(boolean fullscreen) {
         setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
         mIsFullscreen = fullscreen;
-        setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
+        setTaskbarWindowSize(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenSize);
     }
 
     /**
@@ -854,16 +937,20 @@
     }
 
     /**
-     * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset).
+     * Updates the TaskbarContainer size (pass {@link #getDefaultTaskbarWindowSize()} to reset).
      */
-    public void setTaskbarWindowHeight(int height) {
-        if (mWindowLayoutParams.height == height || mIsDestroyed) {
+    public void setTaskbarWindowSize(int size) {
+        // In landscape phone button nav mode, we should set the task bar width instead of height
+        // because this is the only case in which the nav bar is not on the display bottom.
+        boolean landscapePhoneButtonNav = isPhoneButtonNavMode() && mDeviceProfile.isLandscape;
+        if ((landscapePhoneButtonNav ? mWindowLayoutParams.width : mWindowLayoutParams.height)
+                == size || mIsDestroyed) {
             return;
         }
-        if (height == MATCH_PARENT) {
-            height = mDeviceProfile.heightPx;
+        if (size == MATCH_PARENT) {
+            size = mDeviceProfile.heightPx;
         } else {
-            mLastRequestedNonFullscreenHeight = height;
+            mLastRequestedNonFullscreenSize = size;
             if (mIsFullscreen) {
                 // We still need to be fullscreen, so defer any change to our height until we call
                 // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
@@ -872,15 +959,26 @@
                 return;
             }
         }
-        mWindowLayoutParams.height = height;
+        if (landscapePhoneButtonNav) {
+            mWindowLayoutParams.width = size;
+            for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+                mWindowLayoutParams.paramsForRotation[rot].width = size;
+            }
+        } else {
+            mWindowLayoutParams.height = size;
+            for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+                mWindowLayoutParams.paramsForRotation[rot].height = size;
+            }
+        }
         mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
         notifyUpdateLayoutParams();
     }
 
     /**
-     * Returns the default height of the window, including the static corner radii above taskbar.
+     * Returns the default size (in most cases height, but in 3-button phone mode, width) of the
+     * window, including the static corner radii above taskbar.
      */
-    public int getDefaultTaskbarWindowHeight() {
+    public int getDefaultTaskbarWindowSize() {
         Resources resources = getResources();
 
         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone) {
@@ -890,7 +988,7 @@
         }
 
         if (!isUserSetupComplete()) {
-            return getSetupWindowHeight();
+            return getSetupWindowSize();
         }
 
         boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
@@ -921,7 +1019,7 @@
                 + extraHeightForTaskbarTooltips;
     }
 
-    public int getSetupWindowHeight() {
+    public int getSetupWindowSize() {
         return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame);
     }
 
@@ -1003,20 +1101,19 @@
             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
                     ActivityOptions.makeBasic());
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
-        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_FOLDER) {
+        } else if (tag instanceof FolderInfo) {
             // Tapping an expandable folder icon on Taskbar
             shouldCloseAllOpenViews = false;
             expandFolder((FolderIcon) view);
-        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR) {
+        } else if (tag instanceof AppPairInfo api) {
             // Tapping an app pair icon on Taskbar
             if (recents != null && recents.isSplitSelectionActive()) {
-                // TODO (b/274835596): Implement "can't split with this" bounce animation
                 Toast.makeText(this, "Unable to split with an app pair. Select another app.",
                         Toast.LENGTH_SHORT).show();
             } else {
                 // Else launch the selected app pair
-                launchFromTaskbarPreservingSplitIfVisible(recents, view, fi.contents);
-                mControllers.uiController.onTaskbarIconLaunched(fi);
+                launchFromTaskbar(recents, view, api.getContents());
+                mControllers.uiController.onTaskbarIconLaunched(api);
                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
             }
         } else if (tag instanceof WorkspaceItemInfo) {
@@ -1037,9 +1134,8 @@
                         } else if (info.isPromise()) {
                             TestLogging.recordEvent(
                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
-                            intent = new PackageManagerHelper(this)
-                                    .getMarketIntent(info.getTargetPackage())
-                                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                            intent = ApiWrapper.INSTANCE.get(this).getAppMarketActivityIntent(
+                                    info.getTargetPackage(), Process.myUserHandle());
                             startActivity(intent);
 
                         } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
@@ -1050,8 +1146,7 @@
                             getSystemService(LauncherApps.class)
                                     .startShortcut(packageName, id, null, null, info.user);
                         } else {
-                            launchFromTaskbarPreservingSplitIfVisible(
-                                    recents, view, Collections.singletonList(info));
+                            launchFromTaskbar(recents, view, Collections.singletonList(info));
                         }
 
                     } catch (NullPointerException
@@ -1089,8 +1184,7 @@
                 // If we are selecting a second app for split, launch the split tasks
                 taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
             } else {
-                launchFromTaskbarPreservingSplitIfVisible(
-                        recents, view, Collections.singletonList(info));
+                launchFromTaskbar(recents, view, Collections.singletonList(info));
             }
             mControllers.uiController.onTaskbarIconLaunched(info);
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
@@ -1106,26 +1200,62 @@
     }
 
     /**
-     * Run when the user taps a Taskbar icon while in Overview. If the tapped app is currently
-     * visible to the user in Overview, or is part of a visible split pair, we expand the TaskView
-     * as if the user tapped on it (preserving the split pair). Otherwise, launch it normally
-     * (potentially breaking a split pair).
+     * Runs when the user taps a Taskbar icon in TaskbarActivityContext (Overview or inside an app),
+     * and calls the appropriate method to animate and launch.
      */
-    private void launchFromTaskbarPreservingSplitIfVisible(@Nullable RecentsView recents,
+    private void launchFromTaskbar(@Nullable RecentsView recents, @Nullable View launchingIconView,
+            List<? extends ItemInfo> itemInfos) {
+        if (isInApp()) {
+            launchFromInAppTaskbar(recents, launchingIconView, itemInfos);
+        } else {
+            launchFromOverviewTaskbar(recents, launchingIconView, itemInfos);
+        }
+    }
+
+    /**
+     * Runs when the user taps a Taskbar icon while inside an app.
+     */
+    private void launchFromInAppTaskbar(@Nullable RecentsView recents,
             @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos) {
         if (recents == null) {
             return;
         }
 
-        boolean findExactPairMatch = itemInfos.size() == 2;
+        boolean tappedAppPair = itemInfos.size() == 2;
+
+        if (tappedAppPair) {
+            // If the icon is an app pair, the logic gets a bit complicated because we play
+            // different animations depending on which app (or app pair) is currently running on
+            // screen, so delegate logic to appPairsController.
+            recents.getSplitSelectController().getAppPairsController()
+                    .handleAppPairLaunchInApp((AppPairIcon) launchingIconView, itemInfos);
+        } else {
+            // Tapped a single app, nothing complicated here.
+            startItemInfoActivity(itemInfos.get(0), null /*foundTask*/);
+        }
+    }
+
+    /**
+     * Run when the user taps a Taskbar icon while in Overview. If the tapped app is currently
+     * visible to the user in Overview, or is part of a visible split pair, we expand the TaskView
+     * as if the user tapped on it (preserving the split pair). Otherwise, launch it normally
+     * (potentially breaking a split pair).
+     */
+    private void launchFromOverviewTaskbar(@Nullable RecentsView recents,
+            @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos) {
+        if (recents == null) {
+            return;
+        }
+
+        boolean isLaunchingAppPair = itemInfos.size() == 2;
         // Convert the list of ItemInfo instances to a list of ComponentKeys
         List<ComponentKey> componentKeys =
                 itemInfos.stream().map(ItemInfo::getComponentKey).toList();
         recents.getSplitSelectController().findLastActiveTasksAndRunCallback(
                 componentKeys,
-                findExactPairMatch,
+                isLaunchingAppPair,
                 foundTasks -> {
-                    @Nullable Task foundTask = foundTasks.get(0);
+                    @Nullable Task foundTask = foundTasks[0];
                     if (foundTask != null) {
                         TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
                         if (foundTaskView != null
@@ -1137,24 +1267,50 @@
                         }
                     }
 
-                    if (findExactPairMatch) {
-                        // We did not find the app pair we were looking for, so launch one.
-                        recents.getSplitSelectController().getAppPairsController().launchAppPair(
-                                (AppPairIcon) launchingIconView);
+                    if (isLaunchingAppPair) {
+                        // Finish recents animation if it's running before launching to ensure
+                        // we get both leashes for the animation
+                        mControllers.uiController.setSkipNextRecentsAnimEnd();
+                        recents.switchToScreenshot(() ->
+                                recents.finishRecentsAnimation(true /*toRecents*/,
+                                        false /*shouldPip*/,
+                                        () -> recents
+                                                .getSplitSelectController()
+                                                .getAppPairsController()
+                                                .launchAppPair((AppPairIcon) launchingIconView,
+                                                        -1 /*cuj*/)));
                     } else {
-                        startItemInfoActivity(itemInfos.get(0));
+                        startItemInfoActivity(itemInfos.get(0), foundTask);
                     }
                 }
         );
     }
 
-    private void startItemInfoActivity(ItemInfo info) {
+    /**
+     * Starts an activity with the information provided by the "info" param. However, if
+     * taskInRecents is present, it will prioritize re-launching an existing instance via
+     * {@link ActivityManagerWrapper#startActivityFromRecents(int, ActivityOptions)}
+     */
+    private void startItemInfoActivity(ItemInfo info, @Nullable Task taskInRecents) {
         Intent intent = new Intent(info.getIntent())
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         try {
             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
             if (info.user.equals(Process.myUserHandle())) {
                 // TODO(b/216683257): Use startActivityForResult for search results that require it.
+                if (taskInRecents != null) {
+                    // Re launch instance from recents
+                    ActivityOptionsWrapper opts = getActivityLaunchOptions(null, info);
+                    opts.options.setLaunchDisplayId(
+                            getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
+                    if (ActivityManagerWrapper.getInstance()
+                            .startActivityFromRecents(taskInRecents.key, opts.options)) {
+                        mControllers.uiController.getRecentsView()
+                                .addSideTaskLaunchCallback(opts.onEndCallback);
+                        return;
+                    }
+                }
+
                 startActivity(intent);
             } else {
                 getSystemService(LauncherApps.class).startMainActivity(
@@ -1213,8 +1369,12 @@
      * Called when we want to unstash taskbar when user performs swipes up gesture.
      */
     public void onSwipeToUnstashTaskbar() {
-        VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
+        boolean wasStashed = mControllers.taskbarStashController.isStashed();
         mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
+        boolean isStashed = mControllers.taskbarStashController.isStashed();
+        if (isStashed != wasStashed) {
+            VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
+        }
         mControllers.taskbarEduTooltipController.hide();
     }
 
@@ -1286,6 +1446,16 @@
         }
     }
 
+    /** Unstashes the Bubble Bar if it is stashed. */
+    @VisibleForTesting
+    public void unstashBubbleBarIfStashed() {
+        mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
+            if (bubbleControllers.bubbleStashController.isStashed()) {
+                bubbleControllers.bubbleStashController.showBubbleBar(false);
+            }
+        });
+    }
+
     protected boolean isUserSetupComplete() {
         return mIsUserSetupComplete;
     }
@@ -1374,6 +1544,10 @@
         btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
     }
 
+    public void launchKeyboardFocusedTask() {
+        mControllers.uiController.launchKeyboardFocusedTask();
+    }
+
     public boolean isInApp() {
         return mControllers.taskbarStashController.isInApp();
     }
@@ -1413,4 +1587,13 @@
     public float getStashedTaskbarScale() {
         return mControllers.stashedHandleViewController.getStashedHandleHintScale().value;
     }
+
+    /** Closes the KeyboardQuickSwitchView without an animation if open. */
+    public void closeKeyboardQuickSwitchView() {
+        mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
+    }
+
+    boolean canToggleHomeAllApps() {
+        return mControllers.uiController.canToggleHomeAllApps();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index d6016f1..e290c3f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -23,7 +23,6 @@
 import android.graphics.Path
 import android.graphics.RectF
 import com.android.app.animation.Interpolators
-import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.mapRange
@@ -95,10 +94,10 @@
         setCornerRoundness(DEFAULT_ROUNDNESS)
     }
 
-    fun updateStashedHandleWidth(dp: DeviceProfile, res: Resources) {
+    fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
         stashedHandleWidth =
             res.getDimensionPixelSize(
-                if (TaskbarManager.isPhoneMode(dp)) R.dimen.taskbar_stashed_small_screen
+                if (context.isPhoneMode) R.dimen.taskbar_stashed_small_screen
                 else R.dimen.taskbar_stashed_handle_width
             )
     }
@@ -204,12 +203,7 @@
         val newBackgroundHeight =
             mapRange(progress, backgroundHeightWhileAnimating, maxTransientTaskbarHeight)
         val fullWidth = transientBackgroundBounds.width()
-
-        // .9f is here to restrict min width of the background while animating, so transient
-        // background keeps it pill shape until animation end.
-        val animationWidth =
-            if (DisplayController.isTransientTaskbar(context)) fullWidth.toFloat() * .9f
-            else fullWidth.toFloat()
+        val animationWidth = context.currentTaskbarWidth
         val backgroundWidthWhileAnimating =
             if (isAnimatingPinning) animationWidth else stashedHandleWidth.toFloat()
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index 3f9b66a..12f1e63 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar
 
 import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorSet
 import android.animation.ObjectAnimator
 import android.annotation.SuppressLint
@@ -182,7 +181,7 @@
                     measuredWidth.toFloat(),
                     measuredHeight.toFloat(),
                     (measuredWidth - arrowWidth) / 2, // arrowOffsetX
-                    0f, // arrowOffsetY
+                    -mArrowOffsetVertical.toFloat(), // arrowOffsetY
                     false, // isPointingUp
                     true, // leftAligned
                     context.getColor(R.color.popup_shade_first),
@@ -197,32 +196,19 @@
             mActivityContext.deviceProfile.taskbarIconSize) / 2 + verticalOffsetForPopupView
     }
 
-    override fun animateClose() {
-        if (!mIsOpen) {
-            return
+    override fun onCreateCloseAnimation(anim: AnimatorSet?) {
+        // If taskbar pinning preference changed insert custom close animation for popup menu.
+        if (didPreferenceChange) {
+            mOpenCloseAnimator = getCloseAnimator()
         }
-        if (mOpenCloseAnimator != null) {
-            mOpenCloseAnimator.cancel()
-        }
-        mIsOpen = false
-
-        mOpenCloseAnimator = getCloseAnimator()
-
-        mOpenCloseAnimator.addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationEnd(animation: Animator) {
-                    mOpenCloseAnimator = null
-                    if (mDeferContainerRemoval) {
-                        setVisibility(INVISIBLE)
-                    } else {
-                        closeComplete()
-                    }
-                }
-            }
-        )
         onCloseCallback(didPreferenceChange)
         onCloseCallback = {}
-        mOpenCloseAnimator.start()
+    }
+
+    /** Aligning the view pivot to center for animation. */
+    override fun setPivotForOpenCloseAnimation() {
+        pivotX = measuredWidth / 2f
+        pivotY = measuredHeight.toFloat()
     }
 
     private fun getCloseAnimator(): AnimatorSet {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 6ddf9e9..189b687 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
 import static com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers.ContainerCase.DEVICE_SEARCH_RESULT_CONTAINER;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_DRAGDROP;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -517,6 +518,9 @@
                 // Note, this must be done last to ensure no AutohideSuspendFlags are active, as
                 // that will prevent us from stashing until the timeout.
                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
+
+                mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
+                        .log(LAUNCHER_APP_LAUNCH_DRAGDROP);
             }
         }
     }
@@ -682,15 +686,10 @@
         float toScale = iconSize / mDragIconSize;
         float toAlpha = (target == originalView) ? 1f : 0f;
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            final FloatProp mDx = new FloatProp(fromX, toPosition[0], 0,
-                    ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.FAST_OUT_SLOW_IN);
-            final FloatProp mDy = new FloatProp(fromY, toPosition[1], 0,
-                    ANIM_DURATION_RETURN_ICON_TO_TASKBAR,
-                    FAST_OUT_SLOW_IN);
-            final FloatProp mScale = new FloatProp(1f, toScale, 0,
-                    ANIM_DURATION_RETURN_ICON_TO_TASKBAR, FAST_OUT_SLOW_IN);
-            final FloatProp mAlpha = new FloatProp(1f, toAlpha, 0,
-                    ANIM_DURATION_RETURN_ICON_TO_TASKBAR, Interpolators.ACCELERATE_2);
+            final FloatProp mDx = new FloatProp(fromX, toPosition[0], FAST_OUT_SLOW_IN);
+            final FloatProp mDy = new FloatProp(fromY, toPosition[1], FAST_OUT_SLOW_IN);
+            final FloatProp mScale = new FloatProp(1f, toScale, FAST_OUT_SLOW_IN);
+            final FloatProp mAlpha = new FloatProp(1f, toAlpha, Interpolators.ACCELERATE_2);
             @Override
             public void onUpdate(float percent, boolean initOnly) {
                 animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index a24cf4b..7f201b4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -30,9 +30,12 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.graphics.Insets;
+import androidx.core.view.WindowInsetsCompat;
 
 import com.android.app.viewcapture.SettingsAwareViewCapture;
 import com.android.launcher3.AbstractFloatingView;
@@ -106,11 +109,23 @@
 
     public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
         mControllerCallbacks = callbacks;
-        mBackgroundRenderer.updateStashedHandleWidth(mActivity.getDeviceProfile(), getResources());
+        mBackgroundRenderer.updateStashedHandleWidth(mActivity, getResources());
         recreateControllers();
     }
 
     @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        if (insets != null) {
+            WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets, this);
+            Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
+            if (imeInsets != null) {
+                mControllerCallbacks.onImeInsetChanged();
+            }
+        }
+        return insets;
+    }
+
+    @Override
     public void recreateControllers() {
         mControllers = mControllerCallbacks.getTouchControllers();
     }
@@ -147,6 +162,15 @@
     }
 
     @Override
+    protected boolean isEventWithinSystemGestureRegion(MotionEvent ev) {
+        final float x = ev.getX();
+        final float y = ev.getY();
+
+        return x >= mSystemGestureRegion.left && x < getWidth() - mSystemGestureRegion.right
+                && y >= mSystemGestureRegion.top;
+    }
+
+    @Override
     protected boolean canFindActiveController() {
         // Unlike super class, we want to be able to find controllers when touches occur in the
         // gesture area. For example, this allows Folder to close itself when touching the Taskbar.
@@ -169,6 +193,7 @@
         mBackgroundRenderer.setBackgroundProgress(mTaskbarBackgroundProgress);
         mBackgroundRenderer.draw(canvas);
         super.dispatchDraw(canvas);
+        mControllerCallbacks.drawDebugUi(canvas);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 73e32ab..ff890fb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -19,8 +19,10 @@
 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
 
 import android.content.res.Resources;
+import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.SystemProperties;
 import android.view.ViewTreeObserver;
 
 import com.android.launcher3.DeviceProfile;
@@ -39,6 +41,9 @@
 public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController,
         TaskbarControllers.BackgroundRendererController {
 
+    private static final boolean DEBUG = SystemProperties.getBoolean(
+            "persist.debug.draw_taskbar_debug_ui", false);
+
     private final TaskbarActivityContext mActivity;
     private final TaskbarDragLayer mTaskbarDragLayer;
     private final int mFolderMargin;
@@ -265,6 +270,13 @@
         }
 
         /**
+         * Called when an IME inset is changed.
+         */
+        public void onImeInsetChanged() {
+            mControllers.taskbarStashController.onImeInsetChanged();
+        }
+
+        /**
          * Called when a child is removed from TaskbarDragLayer.
          */
         public void onDragLayerViewRemoved() {
@@ -276,11 +288,10 @@
          */
         public int getTaskbarBackgroundHeight() {
             DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-            if (TaskbarManager.isPhoneMode(deviceProfile)) {
+            if (mActivity.isPhoneMode()) {
                 Resources resources = mActivity.getResources();
-                Point taskbarDimensions =
-                        DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
-                                TaskbarManager.isPhoneMode(deviceProfile));
+                Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile,
+                        resources, true /* isPhoneMode */);
                 return taskbarDimensions.y == -1 ?
                         deviceProfile.getDisplayInfo().currentSize.y :
                         taskbarDimensions.y;
@@ -300,5 +311,15 @@
                     mTaskbarStashViaTouchController,
             };
         }
+
+        /**
+         * Draws debug UI on top of everything in TaskbarDragLayer.
+         */
+        public void drawDebugUi(Canvas canvas) {
+            if (!DEBUG) {
+                return;
+            }
+            mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas);
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index 6d1b558..e53f627 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -15,7 +15,13 @@
  */
 package com.android.launcher3.taskbar
 
+import android.content.Intent
+import android.net.Uri
 import android.os.Bundle
+import android.text.SpannableString
+import android.text.method.LinkMovementMethod
+import android.text.style.URLSpan
+import android.view.Gravity
 import android.view.View
 import android.view.View.GONE
 import android.view.View.VISIBLE
@@ -23,18 +29,22 @@
 import android.view.ViewGroup.MarginLayoutParams
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.TextView
 import androidx.annotation.IntDef
 import androidx.annotation.LayoutRes
+import androidx.core.text.HtmlCompat
 import androidx.core.view.updateLayoutParams
 import com.airbnb.lottie.LottieAnimationView
+import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
-import com.android.launcher3.config.FeatureFlags.enableTaskbarPinningEdu
+import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
 import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
-import com.android.launcher3.taskbar.TaskbarManager.isPhoneMode
 import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN
 import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.util.LottieAnimationColorUtils
 import java.io.PrintWriter
 
@@ -51,6 +61,10 @@
  * This value should match the maximum count for [TASKBAR_EDU_TOOLTIP_STEP].
  */
 const val TOOLTIP_STEP_NONE = 3
+/** The base URL for the Privacy Policy that will later be localized. */
+private const val PRIVACY_POLICY_BASE_URL = "https://policies.google.com/privacy/embedded?hl="
+/** The base URL for the Terms of Service that will later be localized. */
+private const val TOS_BASE_URL = "https://policies.google.com/terms?hl="
 
 /** Current step in the tooltip EDU flow. */
 @Retention(AnnotationRetention.SOURCE)
@@ -62,13 +76,22 @@
     LoggableTaskbarController {
 
     private val isTooltipEnabled: Boolean
-        get() = !Utilities.isRunningInTestHarness() && !isPhoneMode(activityContext.deviceProfile)
+        get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
     private val isOpen: Boolean
         get() = tooltip?.isOpen ?: false
     val isBeforeTooltipFeaturesStep: Boolean
         get() = isTooltipEnabled && tooltipStep <= TOOLTIP_STEP_FEATURES
     private lateinit var controllers: TaskbarControllers
 
+    // Keep track of whether the user has seen the Circle to Search Edu
+    private var userHasSeenCircleToSearchEdu: Boolean
+        get() {
+            return TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN.get(activityContext)
+        }
+        private set(seen) {
+            LauncherPrefs.get(activityContext).put(TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN, seen)
+        }
+
     @TaskbarEduTooltipStep
     var tooltipStep: Int
         get() {
@@ -82,6 +105,8 @@
 
     fun init(controllers: TaskbarControllers) {
         this.controllers = controllers
+        // We want to show the Circle To Search Edu right after pinning, so we post it here
+        activityContext.dragLayer.post { maybeShowCircleToSearchEdu() }
     }
 
     /** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
@@ -110,6 +135,8 @@
      */
     fun maybeShowFeaturesEdu() {
         if (!isTooltipEnabled || tooltipStep > TOOLTIP_STEP_FEATURES) {
+            maybeShowPinningEdu()
+            maybeShowCircleToSearchEdu()
             return
         }
 
@@ -126,7 +153,7 @@
             if (DisplayController.isTransientTaskbar(activityContext)) {
                 splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
                 suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
-                pinningEdu.visibility = if (enableTaskbarPinningEdu()) VISIBLE else GONE
+                pinningEdu.visibility = if (enableTaskbarPinning()) VISIBLE else GONE
             } else {
                 splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_persistent)
                 suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_persistent)
@@ -139,7 +166,7 @@
                 if (DisplayController.isTransientTaskbar(activityContext)) {
                     width =
                         resources.getDimensionPixelSize(
-                            if (enableTaskbarPinningEdu())
+                            if (enableTaskbarPinning())
                                 R.dimen.taskbar_edu_features_tooltip_width_with_three_features
                             else R.dimen.taskbar_edu_features_tooltip_width_with_two_features
                         )
@@ -158,6 +185,143 @@
         }
     }
 
+    /**
+     * Shows standalone Pinning EDU tooltip if this EDU has not been seen.
+     *
+     * We show this standalone edu if users have seen the previous version of taskbar education,
+     * which did not include the pinning feature.
+     */
+    private fun maybeShowPinningEdu() {
+        // use old value of tooltipStep that was set to the previous value of TOOLTIP_STEP_NONE (2
+        // for the original 2 edu steps) as a proxy to needing to show the separate pinning edu
+        if (
+            !enableTaskbarPinning() ||
+                !DisplayController.isTransientTaskbar(activityContext) ||
+                !isTooltipEnabled ||
+                tooltipStep > TOOLTIP_STEP_PINNING ||
+                tooltipStep < TOOLTIP_STEP_FEATURES
+        ) {
+            return
+        }
+        tooltipStep = TOOLTIP_STEP_NONE
+        inflateTooltip(R.layout.taskbar_edu_pinning)
+
+        tooltip?.run {
+            requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
+                .supportLightTheme()
+
+            updateLayoutParams<BaseDragLayer.LayoutParams> {
+                if (DisplayController.isTransientTaskbar(activityContext)) {
+                    bottomMargin += activityContext.deviceProfile.taskbarHeight
+                }
+                // Unlike other tooltips, we want to align with taskbar divider rather than center.
+                gravity = Gravity.BOTTOM
+                marginStart = 0
+                width =
+                    resources.getDimensionPixelSize(
+                        R.dimen.taskbar_edu_features_tooltip_width_with_one_feature
+                    )
+            }
+
+            // Calculate the amount the tooltip must be shifted by to align with the taskbar divider
+            val taskbarDividerView = controllers.taskbarViewController.taskbarDividerView
+            val dividerLocation = taskbarDividerView.x + taskbarDividerView.width / 2
+            x = dividerLocation - layoutParams.width / 2
+
+            show()
+        }
+    }
+
+    /**
+     * Shows standalone Circle To Search EDU tooltip if this EDU has not been seen.
+     *
+     * We show this standalone edu for users to learn to how to trigger Circle To Search from the
+     * pinned taskbar
+     */
+    fun maybeShowCircleToSearchEdu() {
+        if (
+            !enableTaskbarPinning() ||
+                !DisplayController.isPinnedTaskbar(activityContext) ||
+                !isTooltipEnabled ||
+                userHasSeenCircleToSearchEdu
+        ) {
+            return
+        }
+        userHasSeenCircleToSearchEdu = true
+        inflateTooltip(R.layout.taskbar_edu_circle_to_search)
+        tooltip?.run {
+            requireViewById<LottieAnimationView>(R.id.circle_to_search_animation)
+                .supportLightTheme()
+            val eduSubtitle: TextView = requireViewById(R.id.circle_to_search_text)
+            showDisclosureText(eduSubtitle)
+            updateLayoutParams<BaseDragLayer.LayoutParams> {
+                if (DisplayController.isTransientTaskbar(activityContext)) {
+                    bottomMargin += activityContext.deviceProfile.taskbarHeight
+                }
+                // Unlike other tooltips, we want to align with the all apps button rather than
+                // center.
+                gravity = Gravity.BOTTOM
+                marginStart = 0
+                width =
+                    resources.getDimensionPixelSize(
+                        R.dimen.taskbar_edu_features_tooltip_width_with_one_feature
+                    )
+            }
+
+            // Calculate the amount the tooltip must be shifted by to align with the action key
+            val allAppsButtonView = controllers.taskbarViewController.allAppsButtonView
+            if (allAppsButtonView != null) {
+                val allAppsIconLocation = allAppsButtonView.x + allAppsButtonView.width / 2
+                x = allAppsIconLocation - layoutParams.width / 2
+            }
+
+            show()
+        }
+    }
+
+    /**
+     * Set up the provided TextView to display legal disclosures. The method takes locale into
+     * account to show the appropriate links to regional disclosures.
+     */
+    private fun TaskbarEduTooltip.showDisclosureText(
+        textView: TextView,
+        stringId: Int = R.string.taskbar_edu_circle_to_search_disclosure,
+    ) {
+        val locale = resources.configuration.locales[0]
+        val text =
+            SpannableString(
+                HtmlCompat.fromHtml(
+                    resources.getString(
+                        stringId,
+                        PRIVACY_POLICY_BASE_URL + locale.language,
+                        TOS_BASE_URL + locale.language,
+                    ),
+                    HtmlCompat.FROM_HTML_MODE_COMPACT,
+                )
+            )
+        // Directly process URLSpan clicks
+        text.getSpans(0, text.length, URLSpan::class.java).forEach { urlSpan ->
+            val url: URLSpan =
+                object : URLSpan(urlSpan.url) {
+                    override fun onClick(widget: View) {
+                        val uri = Uri.parse(urlSpan.url)
+                        val context = widget.context
+                        val intent =
+                            Intent(Intent.ACTION_VIEW, uri).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                        context.startActivity(intent)
+                    }
+                }
+
+            val spanStart = text.getSpanStart(urlSpan)
+            val spanEnd = text.getSpanEnd(urlSpan)
+            val spanFlags = text.getSpanFlags(urlSpan)
+            text.removeSpan(urlSpan)
+            text.setSpan(url, spanStart, spanEnd, spanFlags)
+        }
+        textView.text = text
+        textView.movementMethod = LinkMovementMethod.getInstance()
+    }
+
     /** Closes the current [tooltip]. */
     fun hide() = tooltip?.close(true)
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 1a34b7a..6163dad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -15,16 +15,23 @@
  */
 package com.android.launcher3.taskbar
 
+import android.graphics.Canvas
+import android.graphics.Color
 import android.graphics.Insets
+import android.graphics.Paint
+import android.graphics.Rect
 import android.graphics.Region
 import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
 import android.os.Binder
 import android.os.IBinder
+import android.view.DisplayInfo
 import android.view.Gravity
 import android.view.InsetsFrameProvider
 import android.view.InsetsFrameProvider.SOURCE_DISPLAY
+import android.view.InsetsSource.FLAG_ANIMATE_RESIZING
 import android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER
 import android.view.InsetsSource.FLAG_SUPPRESS_SCRIM
+import android.view.Surface
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
@@ -47,6 +54,7 @@
 import com.android.launcher3.util.DisplayController
 import java.io.PrintWriter
 import kotlin.jvm.optionals.getOrNull
+import kotlin.math.max
 
 /** Handles the insets that Taskbar provides to underlying apps and the IME. */
 class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -58,7 +66,8 @@
 
     /** The bottom insets taskbar provides to the IME when IME is visible. */
     val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
-    private val touchableRegion: Region = Region()
+    // The touchableRegion we will set unless some other state takes precedence.
+    private val defaultTouchableRegion: Region = Region()
     private val insetsOwner: IBinder = Binder()
     private val deviceProfileChangeListener = { _: DeviceProfile ->
         onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
@@ -69,6 +78,7 @@
             context,
             this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged
         )
+    private val debugTouchableRegion = DebugTouchableRegion()
 
     // Initialized in init.
     private lateinit var controllers: TaskbarControllers
@@ -100,18 +110,18 @@
             }
 
         windowLayoutParams.providedInsets =
-            if (enableTaskbarNoRecreate()) {
-                getProvidedInsets(controllers.sharedState!!.insetsFrameProviders!!,
-                        insetsRoundedCornerFlag)
+            if (enableTaskbarNoRecreate() && controllers.sharedState != null) {
+                getProvidedInsets(
+                    controllers.sharedState!!.insetsFrameProviders,
+                    insetsRoundedCornerFlag
+                )
             } else {
                 getProvidedInsets(insetsRoundedCornerFlag)
             }
 
-        if (!context.isGestureNav) {
-            if (windowLayoutParams.paramsForRotation != null) {
-                for (layoutParams in windowLayoutParams.paramsForRotation) {
-                    layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
-                }
+        if (windowLayoutParams.paramsForRotation != null) {
+            for (layoutParams in windowLayoutParams.paramsForRotation) {
+                layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
             }
         }
 
@@ -122,7 +132,7 @@
             } else {
                 0
             }
-        val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight)
+        val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
 
         if (
             controllers.bubbleControllers.isPresent &&
@@ -130,14 +140,14 @@
         ) {
             val iconBounds =
                 controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
-            touchableRegion.set(
+            defaultTouchableRegion.set(
                 iconBounds.left,
                 iconBounds.top,
                 iconBounds.right,
                 iconBounds.bottom
             )
         } else {
-            touchableRegion.set(
+            defaultTouchableRegion.set(
                 0,
                 windowLayoutParams.height - touchableHeight,
                 context.deviceProfile.widthPx,
@@ -145,38 +155,35 @@
             )
         }
 
-        val gravity = windowLayoutParams.gravity
-        for (provider in windowLayoutParams.providedInsets) {
-            setProviderInsets(provider, gravity)
-        }
-
-        if (windowLayoutParams.paramsForRotation != null) {
+        // Pre-calculate insets for different providers across different rotations for this gravity
+        for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
             // Add insets for navbar rotated params
-            for (layoutParams in windowLayoutParams.paramsForRotation) {
-                for (provider in layoutParams.providedInsets) {
-                    setProviderInsets(provider, layoutParams.gravity)
-                }
+            val layoutParams = windowLayoutParams.paramsForRotation[rotation]
+            for (provider in layoutParams.providedInsets) {
+                setProviderInsets(provider, layoutParams.gravity, rotation)
             }
         }
-
+        // Also set the parent providers (i.e. not in paramsForRotation).
+        for (provider in windowLayoutParams.providedInsets) {
+            setProviderInsets(provider, windowLayoutParams.gravity, context.display.rotation)
+        }
         context.notifyUpdateLayoutParams()
     }
 
     /**
      * This is for when ENABLE_TASKBAR_NO_RECREATION is enabled. We generate one instance of
-     * providedInsets and use it across the entire lifecycle of TaskbarManager. The only thing
-     * we need to reset is nav bar flags based on insetsRoundedCornerFlag.
+     * providedInsets and use it across the entire lifecycle of TaskbarManager. The only thing we
+     * need to reset is nav bar flags based on insetsRoundedCornerFlag.
      */
-    private fun getProvidedInsets(providedInsets: Array<InsetsFrameProvider>,
-                                  insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
+    private fun getProvidedInsets(
+        providedInsets: Array<InsetsFrameProvider>,
+        insetsRoundedCornerFlag: Int
+    ): Array<InsetsFrameProvider> {
         val navBarsFlag =
-                (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
+            (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
         for (provider in providedInsets) {
             if (provider.type == navigationBars()) {
-                provider.setFlags(
-                        navBarsFlag,
-                        FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
-                )
+                provider.setFlags(navBarsFlag, FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER)
             }
         }
         return providedInsets
@@ -184,78 +191,85 @@
 
     /**
      * The inset types and number of insets provided have to match for both gesture nav and button
-     * nav. The values and the order of the elements in array are allowed to differ.
-     * Reason being WM does not allow types and number of insets changing for a given window once it
-     * is added into the hierarchy for performance reasons.
+     * nav. The values and the order of the elements in array are allowed to differ. Reason being WM
+     * does not allow types and number of insets changing for a given window once it is added into
+     * the hierarchy for performance reasons.
      */
     private fun getProvidedInsets(insetsRoundedCornerFlag: Int): Array<InsetsFrameProvider> {
         val navBarsFlag =
-                (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM else 0) or insetsRoundedCornerFlag
+            (if (context.isGestureNav) FLAG_SUPPRESS_SCRIM or FLAG_ANIMATE_RESIZING else 0) or
+                insetsRoundedCornerFlag
         return arrayOf(
-                InsetsFrameProvider(insetsOwner, 0, navigationBars())
-                        .setFlags(
-                                navBarsFlag,
-                                FLAG_SUPPRESS_SCRIM or FLAG_INSETS_ROUNDED_CORNER
-                        ),
-                InsetsFrameProvider(insetsOwner, 0, tappableElement()),
-                InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
-                InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
-                        .setSource(SOURCE_DISPLAY),
-                InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
-                        .setSource(SOURCE_DISPLAY)
+            InsetsFrameProvider(insetsOwner, 0, navigationBars())
+                .setFlags(
+                    navBarsFlag,
+                    FLAG_SUPPRESS_SCRIM or FLAG_ANIMATE_RESIZING or FLAG_INSETS_ROUNDED_CORNER
+                ),
+            InsetsFrameProvider(insetsOwner, 0, tappableElement()),
+            InsetsFrameProvider(insetsOwner, 0, mandatorySystemGestures()),
+            InsetsFrameProvider(insetsOwner, INDEX_LEFT, systemGestures())
+                .setSource(SOURCE_DISPLAY),
+            InsetsFrameProvider(insetsOwner, INDEX_RIGHT, systemGestures())
+                .setSource(SOURCE_DISPLAY)
         )
     }
 
-    private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int) {
+    private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int, endRotation: Int) {
         val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
         val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
         val res = context.resources
         if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
-            provider.insetsSize = getInsetsForGravity(contentHeight, gravity)
+            provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
         } else if (provider.type == tappableElement()) {
             provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
         } else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
             val leftIndexInset =
-                    if (context.isThreeButtonNav) 0
-                    else gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res)
+                if (context.isThreeButtonNav) 0
+                else gestureNavSettingsObserver.getLeftSensitivityForCallingUser(res)
             provider.insetsSize = Insets.of(leftIndexInset, 0, 0, 0)
         } else if (provider.type == systemGestures() && provider.index == INDEX_RIGHT) {
             val rightIndexInset =
-                    if (context.isThreeButtonNav) 0
-                    else gestureNavSettingsObserver.getRightSensitivityForCallingUser(res)
+                if (context.isThreeButtonNav) 0
+                else gestureNavSettingsObserver.getRightSensitivityForCallingUser(res)
             provider.insetsSize = Insets.of(0, 0, rightIndexInset, 0)
         }
 
         // When in gesture nav, report the stashed height to the IME, to allow hiding the
         // IME navigation bar.
-        val imeInsetsSize = if (ENABLE_HIDE_IME_CAPTION_BAR && context.isGestureNav) {
-            getInsetsForGravity(controllers.taskbarStashController.stashedHeight, gravity);
-        } else {
-            getInsetsForGravity(taskbarHeightForIme, gravity)
-        }
+        val imeInsetsSize =
+            if (ENABLE_HIDE_IME_CAPTION_BAR && context.isGestureNav) {
+                getInsetsForGravity(controllers.taskbarStashController.stashedHeight, gravity)
+            } else {
+                getInsetsForGravity(taskbarHeightForIme, gravity)
+            }
         val imeInsetsSizeOverride =
-                arrayOf(
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_VOICE_INTERACTION,
-                                // No-op override to keep the size and types in sync with the
-                                // override below (insetsSizeOverrides must have the same length and
-                                // types after the window is added according to
-                                // WindowManagerService#relayoutWindow)
-                                provider.insetsSize)
+            arrayOf(
+                InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+                InsetsFrameProvider.InsetsSizeOverride(
+                    TYPE_VOICE_INTERACTION,
+                    // No-op override to keep the size and types in sync with the
+                    // override below (insetsSizeOverrides must have the same length and
+                    // types after the window is added according to
+                    // WindowManagerService#relayoutWindow)
+                    provider.insetsSize
                 )
+            )
         // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
         val visInsetsSizeForTappableElement =
-                if (context.isGestureNav) getInsetsForGravity(0, gravity)
-                else getInsetsForGravity(tappableHeight, gravity)
+            if (context.isGestureNav) getInsetsForGravity(0, gravity)
+            else getInsetsForGravity(tappableHeight, gravity)
         val insetsSizeOverrideForTappableElement =
-                arrayOf(
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_VOICE_INTERACTION,
-                                visInsetsSizeForTappableElement
-                        ),
-                )
-        if ((context.isGestureNav || ENABLE_TASKBAR_NAVBAR_UNIFICATION)
-                && provider.type == tappableElement()) {
+            arrayOf(
+                InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+                InsetsFrameProvider.InsetsSizeOverride(
+                    TYPE_VOICE_INTERACTION,
+                    visInsetsSizeForTappableElement
+                ),
+            )
+        if (
+            (context.isGestureNav || ENABLE_TASKBAR_NAVBAR_UNIFICATION) &&
+                provider.type == tappableElement()
+        ) {
             provider.insetsSizeOverrides = insetsSizeOverrideForTappableElement
         } else if (provider.type != systemGestures()) {
             // We only override insets at the bottom of the screen
@@ -264,8 +278,32 @@
     }
 
     /**
-     * @return [Insets] where the [inset] is either used as a bottom inset or
-     * right/left inset if using 3 button nav
+     * Calculate the [Insets] for taskbar after a rotation, specifically for any potential cutouts
+     * in the screen that can come from the camera.
+     */
+    private fun getInsetsForGravityWithCutout(inset: Int, gravity: Int, rot: Int): Insets {
+        val display = context.display
+        // If there is no cutout, fall back to the original method of calculating insets
+        val cutout = display.cutout ?: return getInsetsForGravity(inset, gravity)
+        val rotation = display.rotation
+        val info = DisplayInfo()
+        display.getDisplayInfo(info)
+        val rotatedCutout = cutout.getRotated(info.logicalWidth, info.logicalHeight, rotation, rot)
+
+        if ((gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
+            return Insets.of(0, 0, 0, maxOf(inset, rotatedCutout.safeInsetBottom))
+        }
+
+        // TODO(b/230394142): seascape
+        val isSeascape = (gravity and Gravity.START) == Gravity.START
+        val leftInset = if (isSeascape) maxOf(inset, rotatedCutout.safeInsetLeft) else 0
+        val rightInset = if (isSeascape) 0 else maxOf(inset, rotatedCutout.safeInsetRight)
+        return Insets.of(leftInset, 0, rightInset, 0)
+    }
+
+    /**
+     * @return [Insets] where the [inset] is either used as a bottom inset or right/left inset if
+     *   using 3 button nav
      */
     private fun getInsetsForGravity(inset: Int, gravity: Int): Insets {
         if ((gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
@@ -277,7 +315,7 @@
         val isSeascape = (gravity and Gravity.START) == Gravity.START
         val leftInset = if (isSeascape) inset else 0
         val rightInset = if (isSeascape) 0 else inset
-        return Insets.of(leftInset , 0, rightInset, 0)
+        return Insets.of(leftInset, 0, rightInset, 0)
     }
 
     /**
@@ -292,28 +330,44 @@
             context.dragLayer,
             insetsInfo.touchableRegion
         )
+        debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
+
         val bubbleBarVisible =
             controllers.bubbleControllers.isPresent &&
                 controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
         var insetsIsTouchableRegion = true
-        if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
+        if (
+            context.isPhoneButtonNavMode &&
+                (!controllers.navbarButtonsViewController.isImeVisible ||
+                    !controllers.navbarButtonsViewController.isImeRenderingNavButtons)
+        ) {
+            insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
+            insetsIsTouchableRegion = false
+        } else if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
             // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+            debugTouchableRegion.lastSetTouchableReason = "Taskbar is invisible"
         } else if (
             controllers.navbarButtonsViewController.isImeVisible &&
                 controllers.taskbarStashController.isStashed
         ) {
+            // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+            debugTouchableRegion.lastSetTouchableReason = "Stashed over IME"
         } else if (!controllers.uiController.isTaskbarTouchable) {
             // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+            debugTouchableRegion.lastSetTouchableReason = "Taskbar is not touchable"
         } else if (controllers.taskbarDragController.isSystemDragInProgress) {
             // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+            debugTouchableRegion.lastSetTouchableReason = "System drag is in progress"
         } else if (context.isTaskbarWindowFullscreen) {
             // Intercept entire fullscreen window.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
             insetsIsTouchableRegion = false
+            debugTouchableRegion.lastSetTouchableReason = "Taskbar is fullscreen"
+            context.dragLayer.getBoundsInWindow(debugTouchableRegion.lastSetTouchableBounds, false)
         } else if (
             controllers.taskbarViewController.areIconsVisible() ||
                 context.isNavBarKidsModeActive ||
@@ -321,7 +375,7 @@
         ) {
             // Taskbar has some touchable elements, take over the full taskbar area
             if (
-                controllers.uiController.isInOverview &&
+                controllers.uiController.isInOverviewUi &&
                     DisplayController.isTransientTaskbar(context)
             ) {
                 val region =
@@ -342,19 +396,33 @@
                     region.op(bubbleBarBounds, Region.Op.UNION)
                 }
                 insetsInfo.touchableRegion.set(region)
+                debugTouchableRegion.lastSetTouchableReason = "Transient Taskbar is in Overview"
+                debugTouchableRegion.lastSetTouchableBounds.set(region.bounds)
             } else {
-                insetsInfo.touchableRegion.set(touchableRegion)
+                insetsInfo.touchableRegion.set(defaultTouchableRegion)
+                debugTouchableRegion.lastSetTouchableReason = "Using default touchable region"
+                debugTouchableRegion.lastSetTouchableBounds.set(defaultTouchableRegion.bounds)
             }
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
             insetsIsTouchableRegion = false
         } else {
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
+            debugTouchableRegion.lastSetTouchableReason =
+                "Icons are not visible, but other components such as 3 buttons might be"
         }
         context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
     }
 
+    /** Draws the last set touchableRegion as a red rectangle onto the given Canvas. */
+    fun drawDebugTouchableRegionBounds(canvas: Canvas) {
+        val paint = Paint()
+        paint.color = Color.RED
+        paint.style = Paint.Style.STROKE
+        canvas.drawRect(debugTouchableRegion.lastSetTouchableBounds, paint)
+    }
+
     override fun dumpLogs(prefix: String, pw: PrintWriter) {
-        pw.println(prefix + "TaskbarInsetsController:")
+        pw.println("${prefix}TaskbarInsetsController:")
         pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
         for (provider in windowLayoutParams.providedInsets) {
             pw.print(
@@ -373,5 +441,12 @@
             }
             pw.println()
         }
+        pw.println("$prefix\tlastSetTouchableBounds=${debugTouchableRegion.lastSetTouchableBounds}")
+        pw.println("$prefix\tlastSetTouchableReason=${debugTouchableRegion.lastSetTouchableReason}")
+    }
+
+    class DebugTouchableRegion {
+        val lastSetTouchableBounds = Rect()
+        var lastSetTouchableReason = ""
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 057b71b..ee21eac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -17,7 +17,6 @@
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
-import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
@@ -149,6 +148,7 @@
     private Integer mPrevState;
     private int mState;
     private LauncherState mLauncherState = LauncherState.NORMAL;
+    private boolean mSkipNextRecentsAnimEnd;
 
     // Time when FLAG_TASKBAR_HIDDEN was last cleared, SystemClock.elapsedRealtime (milliseconds).
     private long mLastUnlockTimeMs = 0;
@@ -194,7 +194,7 @@
                     updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
                     if (!mShouldDelayLauncherStateAnim) {
                         if (toState == LauncherState.NORMAL) {
-                            applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
+                            applyState(QuickstepTransitionManager.getTaskbarToHomeDuration());
                         } else {
                             applyState();
                         }
@@ -206,13 +206,7 @@
                     mLauncherState = finalState;
                     updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
                     applyState();
-                    boolean disallowLongClick =
-                            FeatureFlags.enableSplitContextually()
-                                    ? mLauncher.isSplitSelectionEnabled()
-                                    : finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
-                    com.android.launcher3.taskbar.Utilities.setOverviewDragState(
-                            mControllers, finalState.disallowTaskbarGlobalDrag(),
-                            disallowLongClick, finalState.allowTaskbarInitialSplitSelection());
+                    updateOverviewDragState(finalState);
                 }
             };
 
@@ -223,8 +217,7 @@
     public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
         // TODO(b/279514548) Cleans up bad state that can occur when user interacts with
         // taskbar on top of transparent activity.
-        if (!FeatureFlags.enableHomeTransitionListener()
-                && (finalState == LauncherState.NORMAL)
+        if ((finalState == LauncherState.NORMAL)
                 && mLauncher.hasBeenResumed()) {
             updateStateForFlag(FLAG_VISIBLE, true);
             applyState();
@@ -258,6 +251,7 @@
 
         mCanSyncViews = true;
         mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+        updateOverviewDragState(mLauncherState);
     }
 
     public void onDestroy() {
@@ -299,12 +293,16 @@
 
         if (mTaskBarRecentsAnimationListener != null) {
             mTaskBarRecentsAnimationListener.endGestureStateOverride(
-                    !mLauncher.isInState(LauncherState.OVERVIEW));
+                    !mLauncher.isInState(LauncherState.OVERVIEW), false /*canceled*/);
         }
         mTaskBarRecentsAnimationListener = new TaskBarRecentsAnimationListener(callbacks);
         callbacks.addListener(mTaskBarRecentsAnimationListener);
         ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(() ->
-                mTaskBarRecentsAnimationListener.endGestureStateOverride(true));
+                mTaskBarRecentsAnimationListener.endGestureStateOverride(true, false /*canceled*/));
+
+        ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchCancelledRunnable(() -> {
+            updateStateForUserFinishedToApp(false /* finishedToApp */);
+        });
         return animatorSet;
     }
 
@@ -321,12 +319,17 @@
         mShouldDelayLauncherStateAnim = shouldDelayLauncherStateAnim;
     }
 
+    /** Will make the next onRecentsAnimationFinished() a no-op. */
+    public void setSkipNextRecentsAnimEnd() {
+        mSkipNextRecentsAnimEnd = true;
+    }
+
     /** SysUI flags updated, see QuickStepContract.SYSUI_STATE_* values. */
     public void updateStateForSysuiFlags(int systemUiStateFlags) {
         updateStateForSysuiFlags(systemUiStateFlags, /* applyState */ true);
     }
 
-    private  void updateStateForSysuiFlags(int systemUiStateFlags, boolean applyState) {
+    private void updateStateForSysuiFlags(int systemUiStateFlags, boolean applyState) {
         final boolean prevIsAwake = hasAnyFlag(FLAG_AWAKE);
         final boolean currIsAwake = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_AWAKE);
 
@@ -356,6 +359,21 @@
     }
 
     /**
+     * Updates overview drag state on various controllers based on {@link #mLauncherState}.
+     *
+     * @param launcherState The current state launcher is in
+     */
+    private void updateOverviewDragState(LauncherState launcherState) {
+        boolean disallowLongClick =
+                FeatureFlags.enableSplitContextually()
+                        ? mLauncher.isSplitSelectionActive()
+                        : launcherState == LauncherState.OVERVIEW_SPLIT_SELECT;
+        com.android.launcher3.taskbar.Utilities.setOverviewDragState(
+                mControllers, launcherState.disallowTaskbarGlobalDrag(),
+                disallowLongClick, launcherState.allowTaskbarInitialSplitSelection());
+    }
+
+    /**
      * Updates the proper flag to change the state of the task bar.
      *
      * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
@@ -644,11 +662,12 @@
      * Returns if the current Launcher state has hotseat on top of other elemnets.
      */
     public boolean isInHotseatOnTopStates() {
-        return mLauncherState != LauncherState.ALL_APPS;
+        return mLauncherState != LauncherState.ALL_APPS
+                && !mLauncher.getWorkspace().isOverlayShown();
     }
 
-    boolean isInOverview() {
-        return mLauncherState == LauncherState.OVERVIEW;
+    boolean isInOverviewUi() {
+        return mLauncherState.overviewUi;
     }
 
     private void playStateTransitionAnim(AnimatorSet animatorSet, long duration,
@@ -734,7 +753,7 @@
         }
         mIconAlphaForHome.setValue(alpha);
         boolean hotseatVisible = alpha == 0
-                || isPhoneMode(mLauncher.getDeviceProfile())
+                || mControllers.taskbarActivityContext.isPhoneMode()
                 || (!mControllers.uiController.isHotseatIconOnTopWhenAligned()
                 && mIconAlignment.value > 0);
         /*
@@ -758,34 +777,56 @@
         @Override
         public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
             boolean isInOverview = mLauncher.isInState(LauncherState.OVERVIEW);
-            endGestureStateOverride(!isInOverview);
+            endGestureStateOverride(!isInOverview, true /*canceled*/);
         }
 
         @Override
         public void onRecentsAnimationFinished(RecentsAnimationController controller) {
-            endGestureStateOverride(!controller.getFinishTargetIsLauncher());
+            endGestureStateOverride(!controller.getFinishTargetIsLauncher(), false /*canceled*/);
         }
 
-        private void endGestureStateOverride(boolean finishedToApp) {
+        /**
+         * Handles whatever cleanup is needed after the recents animation is completed.
+         * NOTE: If {@link #mSkipNextRecentsAnimEnd} is set and we're coming from a non-cancelled
+         * path, this will not call {@link #updateStateForUserFinishedToApp(boolean)}
+         *
+         * @param finishedToApp {@code true} if the recents animation finished to showing an app and
+         *                      not workspace or overview
+         * @param canceled {@code true} if the recents animation was canceled instead of finishing
+         *                 to completion
+         */
+        private void endGestureStateOverride(boolean finishedToApp, boolean canceled) {
             mCallbacks.removeListener(this);
             mTaskBarRecentsAnimationListener = null;
             ((RecentsView) mLauncher.getOverviewPanel()).setTaskLaunchListener(null);
 
-            // Update the visible state immediately to ensure a seamless handoff
-            boolean launcherVisible = !finishedToApp;
-            updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, false);
-            updateStateForFlag(FLAG_VISIBLE, launcherVisible);
-            applyState();
-
-            TaskbarStashController controller = mControllers.taskbarStashController;
-            if (DEBUG) {
-                Log.d(TAG, "endGestureStateOverride - FLAG_IN_APP: " + finishedToApp);
+            if (mSkipNextRecentsAnimEnd && !canceled) {
+                mSkipNextRecentsAnimEnd = false;
+                return;
             }
-            controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
-            controller.applyState();
+            updateStateForUserFinishedToApp(finishedToApp);
         }
     }
 
+    /**
+     * Updates the visible state immediately to ensure a seamless handoff.
+     * @param finishedToApp True iff user is in an app.
+     */
+    private void updateStateForUserFinishedToApp(boolean finishedToApp) {
+        // Update the visible state immediately to ensure a seamless handoff
+        boolean launcherVisible = !finishedToApp;
+        updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, false);
+        updateStateForFlag(FLAG_VISIBLE, launcherVisible);
+        applyState();
+
+        TaskbarStashController controller = mControllers.taskbarStashController;
+        if (DEBUG) {
+            Log.d(TAG, "endGestureStateOverride - FLAG_IN_APP: " + finishedToApp);
+        }
+        controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
+        controller.applyState();
+    }
+
     private static String getStateString(int flags) {
         StringJoiner result = new StringJoiner("|");
         appendFlag(result, flags, FLAG_VISIBLE, "flag_visible");
@@ -796,6 +837,7 @@
         appendFlag(result, flags, FLAG_LAUNCHER_WAS_ACTIVE_WHILE_AWAKE,
                 "was_active_while_awake");
         appendFlag(result, flags, FLAG_DEVICE_LOCKED, "device_locked");
+        appendFlag(result, flags, FLAG_TASKBAR_HIDDEN, "taskbar_hidden");
         return result.toString();
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index bbac116..e47640b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -22,9 +22,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
 import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
+import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
+import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -55,7 +58,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.statemanager.StatefulActivity;
@@ -64,6 +67,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.quickstep.AllAppsActionManager;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TouchInteractionService;
@@ -71,7 +75,6 @@
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
-import com.android.wm.shell.Flags;
 
 import java.io.PrintWriter;
 import java.util.StringJoiner;
@@ -135,7 +138,17 @@
      * We use WindowManager's ComponentCallbacks() for internal UI changes (similar to an Activity)
      * which comes via a different channel
      */
-    private final OnIDPChangeListener mIdpChangeListener = c -> recreateTaskbar();
+    private final RecreationListener mRecreationListener = new RecreationListener();
+
+    private class RecreationListener implements DisplayController.DisplayInfoChangeListener {
+        @Override
+        public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
+            if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE
+                    | CHANGE_TASKBAR_PINNING)) != 0) {
+                recreateTaskbar();
+            }
+        }
+    }
     private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> recreateTaskbar();
 
     private boolean mUserUnlocked = false;
@@ -143,6 +156,8 @@
     private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
             new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
 
+    private final AllAppsActionManager mAllAppsActionManager;
+
     private final Runnable mActivityOnDestroyCallback = new Runnable() {
         @Override
         public void run() {
@@ -193,12 +208,14 @@
             };
 
     @SuppressLint("WrongConstant")
-    public TaskbarManager(TouchInteractionService service) {
+    public TaskbarManager(
+            TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
         Display display =
                 service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
         mContext = service.createWindowContext(display,
                 ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
                 null);
+        mAllAppsActionManager = allAppsActionManager;
         mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
                 ? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
                 : null;
@@ -249,10 +266,10 @@
                     recreateTaskbar();
                 } else {
                     // Config change might be handled without re-creating the taskbar
-                    if (dp != null && !isTaskbarPresent(dp)) {
+                    if (dp != null && !isTaskbarEnabled(dp)) {
                         destroyExistingTaskbar();
                     } else {
-                        if (dp != null && isTaskbarPresent(dp)) {
+                        if (dp != null && isTaskbarEnabled(dp)) {
                             if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
                                 // Re-initialize for screen size change? Should this be done
                                 // by looking at screen-size change flag in configDiff in the
@@ -266,6 +283,9 @@
                     }
                 }
                 mOldConfig = new Configuration(newConfig);
+                // reset taskbar was pinned value, so we don't automatically unstash taskbar upon
+                // user unfolding the device.
+                mSharedState.setTaskbarWasPinned(false);
             }
 
             @Override
@@ -304,7 +324,7 @@
         }
         DeviceProfile dp = mUserUnlocked ?
                 LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
-        if (dp == null || !isTaskbarPresent(dp)) {
+        if (dp == null || !isTaskbarEnabled(dp)) {
             removeTaskbarRootViewFromWindow();
         }
     }
@@ -320,21 +340,15 @@
 
     /**
      * Toggles All Apps for Taskbar or Launcher depending on the current state.
-     *
-     * @param homeAllAppsIntent Intent used if Taskbar is not enabled or Launcher is resumed.
      */
-    public void toggleAllApps(Intent homeAllAppsIntent) {
-        if (mTaskbarActivityContext == null) {
-            mContext.startActivity(homeAllAppsIntent);
-            return;
+    public void toggleAllApps() {
+        if (mTaskbarActivityContext == null || mTaskbarActivityContext.canToggleHomeAllApps()) {
+            // Home All Apps should be toggled from this class, because the controllers are not
+            // initialized when Taskbar is disabled (i.e. TaskbarActivityContext is null).
+            if (mActivity instanceof Launcher l) l.toggleAllAppsSearch();
+        } else {
+            mTaskbarActivityContext.toggleAllAppsSearch();
         }
-
-        if (mActivity != null && mActivity.isResumed() && !mActivity.isInState(OVERVIEW)) {
-            mContext.startActivity(homeAllAppsIntent);
-            return;
-        }
-
-        mTaskbarActivityContext.toggleAllAppsSearch();
     }
 
     /**
@@ -353,7 +367,7 @@
      */
     public void onUserUnlocked() {
         mUserUnlocked = true;
-        LauncherAppState.getIDP(mContext).addOnChangeListener(mIdpChangeListener);
+        DisplayController.INSTANCE.get(mContext).addChangeListener(mRecreationListener);
         recreateTaskbar();
         addTaskbarRootViewToWindow();
     }
@@ -391,8 +405,12 @@
      */
     private UnfoldTransitionProgressProvider getUnfoldTransitionProgressProviderForActivity(
             StatefulActivity activity) {
-        if (activity instanceof QuickstepLauncher) {
-            return ((QuickstepLauncher) activity).getUnfoldTransitionProgressProvider();
+        if (!enableUnfoldStateAnimation()) {
+            if (activity instanceof QuickstepLauncher ql) {
+                return ql.getUnfoldTransitionProgressProvider();
+            }
+        } else {
+            return SystemUiProxy.INSTANCE.get(mContext).getUnfoldTransitionProvider();
         }
         return null;
     }
@@ -419,15 +437,19 @@
      * In other case (folding/unfolding) we don't need to remove and add window.
      */
     @VisibleForTesting
-    public void recreateTaskbar() {
+    public synchronized void recreateTaskbar() {
         Trace.beginSection("recreateTaskbar");
         try {
             DeviceProfile dp = mUserUnlocked ?
                 LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
 
+            // All Apps action is unrelated to navbar unification, so we only need to check DP.
+            final boolean isLargeScreenTaskbar = dp != null && dp.isTaskbarPresent;
+            mAllAppsActionManager.setTaskbarPresent(isLargeScreenTaskbar);
+
             destroyExistingTaskbar();
 
-            boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp);
+            boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
             debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
                 + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
                 + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
@@ -447,6 +469,7 @@
             }
             mSharedState.startTaskbarVariantIsTransient =
                     DisplayController.isTransientTaskbar(mTaskbarActivityContext);
+            mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
             mTaskbarActivityContext.init(mSharedState);
 
             if (mActivity != null) {
@@ -492,23 +515,7 @@
         }
     }
 
-    /**
-     * @return {@code true} if provided device profile isn't a large screen profile
-     *                      and we are using a single window for taskbar and navbar.
-     */
-    public static boolean isPhoneMode(DeviceProfile deviceProfile) {
-        return ENABLE_TASKBAR_NAVBAR_UNIFICATION && deviceProfile.isPhone;
-    }
-
-    /**
-     * @return {@code true} if {@link #isPhoneMode(DeviceProfile)} is true and we're using
-     *                      3 button-nav
-     */
-    public static boolean isPhoneButtonNavMode(TaskbarActivityContext context) {
-        return isPhoneMode(context.getDeviceProfile()) && context.isThreeButtonNav();
-    }
-
-    private boolean isTaskbarPresent(DeviceProfile deviceProfile) {
+    private static boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
         return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
     }
 
@@ -542,6 +549,14 @@
         }
     }
 
+    public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+        mSharedState.mLumaSamplingDisplayId = displayId;
+        mSharedState.mIsLumaSamplingEnabled = enable;
+        if (mTaskbarActivityContext != null) {
+            mTaskbarActivityContext.onNavigationBarLumaSamplingEnabled(displayId, enable);
+        }
+    }
+
     private void removeActivityCallbacksAndListeners() {
         if (mActivity != null) {
             mActivity.removeOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
@@ -566,8 +581,9 @@
         UI_HELPER_EXECUTOR.execute(
                 () -> mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext));
         destroyExistingTaskbar();
+        removeTaskbarRootViewFromWindow();
         if (mUserUnlocked) {
-            LauncherAppState.getIDP(mContext).removeOnChangeListener(mIdpChangeListener);
+            DisplayController.INSTANCE.get(mContext).removeChangeListener(mRecreationListener);
         }
         SettingsCache.INSTANCE.get(mContext)
                 .unregister(USER_SETUP_COMPLETE_URI, mOnSettingsChangeListener);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 7692760..6c84f80 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -15,6 +15,9 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+
 import android.util.SparseArray;
 import android.view.View;
 
@@ -26,6 +29,7 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -33,6 +37,7 @@
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.RecentsModel;
 
 import java.io.PrintWriter;
@@ -62,6 +67,8 @@
     // Used to defer any UI updates during the SUW unstash animation.
     private boolean mDeferUpdatesForSUW;
     private Runnable mDeferredUpdates;
+    private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+            visible -> updateRunningApps();
 
     public TaskbarModelCallbacks(
             TaskbarActivityContext context, TaskbarView container) {
@@ -73,6 +80,15 @@
         mControllers = controllers;
         if (mControllers.taskbarRecentAppsController.isEnabled()) {
             RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
+
+            if (shouldShowRunningAppsInDesktopMode()) {
+                DesktopVisibilityController desktopVisibilityController =
+                        LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+                if (desktopVisibilityController != null) {
+                    desktopVisibilityController.registerDesktopVisibilityListener(
+                            mDesktopVisibilityListener);
+                }
+            }
         }
     }
 
@@ -81,6 +97,20 @@
      */
     public void unregisterListeners() {
         RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
+
+        if (shouldShowRunningAppsInDesktopMode()) {
+            DesktopVisibilityController desktopVisibilityController =
+                    LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+            if (desktopVisibilityController != null) {
+                desktopVisibilityController.unregisterDesktopVisibilityListener(
+                        mDesktopVisibilityListener);
+            }
+        }
+    }
+
+    private boolean shouldShowRunningAppsInDesktopMode() {
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
     }
 
     @Override
@@ -206,19 +236,12 @@
 
         if (mDeferUpdatesForSUW) {
             ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
-            mDeferredUpdates = () -> {
-                updateHotseatItemsAndBackground(finalHotseatItemInfos);
-            };
+            mDeferredUpdates = () -> mContainer.updateHotseatItems(finalHotseatItemInfos);
         } else {
-            updateHotseatItemsAndBackground(hotseatItemInfos);
+            mContainer.updateHotseatItems(hotseatItemInfos);
         }
     }
 
-    private void updateHotseatItemsAndBackground(ItemInfo[] hotseatItemInfos) {
-        mContainer.updateHotseatItems(hotseatItemInfos);
-        mControllers.taskbarViewController.updateIconsBackground();
-    }
-
     /**
      * This is used to defer UI updates after SUW builds the unstash animation.
      * @param defer if true, defers updates to the UI
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 3f72e5d..03f55ca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -27,7 +27,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
@@ -102,6 +101,7 @@
     static final int BUTTON_A11Y = BUTTON_IME_SWITCH << 1;
     static final int BUTTON_QUICK_SETTINGS = BUTTON_A11Y << 1;
     static final int BUTTON_NOTIFICATIONS = BUTTON_QUICK_SETTINGS << 1;
+    static final int BUTTON_SPACE = BUTTON_NOTIFICATIONS << 1;
 
     private static final int SCREEN_UNPIN_COMBO = BUTTON_BACK | BUTTON_RECENTS;
     private int mLongPressedButtons = 0;
@@ -123,6 +123,9 @@
     }
 
     public void onButtonClick(@TaskbarButton int buttonType, View view) {
+        if (buttonType == BUTTON_SPACE) {
+            return;
+        }
         // Provide the same haptic feedback that the system offers for virtual keys.
         view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
         switch (buttonType) {
@@ -156,6 +159,9 @@
     }
 
     public boolean onButtonLongClick(@TaskbarButton int buttonType, View view) {
+        if (buttonType == BUTTON_SPACE) {
+            return false;
+        }
         // Provide the same haptic feedback that the system offers for virtual keys.
         view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
         switch (buttonType) {
@@ -274,12 +280,10 @@
     private void navigateHome() {
         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
 
-        if (isDesktopModeSupported()) {
-            DesktopVisibilityController desktopVisibilityController =
-                    LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
-            if (desktopVisibilityController != null) {
-                desktopVisibilityController.onHomeActionTriggered();
-            }
+        DesktopVisibilityController desktopVisibilityController =
+                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+        if (desktopVisibilityController != null) {
+            desktopVisibilityController.onHomeActionTriggered();
         }
 
         mService.getOverviewCommandHelper().addCommand(OverviewCommandHelper.TYPE_HOME);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 6cb28ee..2f2d636 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -20,10 +20,13 @@
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import androidx.core.animation.doOnEnd
+import com.android.app.animation.Interpolators
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_UNPINNED
 import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
 import java.io.PrintWriter
 
@@ -53,8 +56,10 @@
                 }
                 val animateToValue =
                     if (!launcherPrefs.get(TASKBAR_PINNING)) {
+                        statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
                         PINNING_PERSISTENT
                     } else {
+                        statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
                         PINNING_TRANSIENT
                     }
                 taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
@@ -106,6 +111,7 @@
             taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
         )
 
+        animatorSet.interpolator = Interpolators.EMPHASIZED
         return animatorSet
     }
 
@@ -129,6 +135,6 @@
     companion object {
         const val PINNING_PERSISTENT = 1f
         const val PINNING_TRANSIENT = 0f
-        const val PINNING_ANIMATION_DURATION = 500L
+        const val PINNING_ANIMATION_DURATION = 600L
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index a667dca..2730be1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -40,7 +40,6 @@
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.popup.PopupDataProvider;
-import com.android.launcher3.popup.PopupLiveUpdateHandler;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.splitscreen.SplitShortcut;
@@ -117,9 +116,9 @@
                 }
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 FolderInfo fi = (FolderInfo) info;
-                if (fi.contents.stream().anyMatch(matcher)) {
+                if (fi.anyMatch(matcher)) {
                     FolderDotInfo folderDotInfo = new FolderDotInfo();
-                    for (WorkspaceItemInfo si : fi.contents) {
+                    for (ItemInfo si : fi.getContents()) {
                         folderDotInfo.addDotInfo(mPopupDataProvider.getDotInfoForItem(si));
                     }
                     ((FolderIcon) v).setDotInfo(folderDotInfo);
@@ -166,13 +165,6 @@
                     R.layout.popup_container, context.getDragLayer(), false);
         container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts);
 
-        container.addOnAttachStateChangeListener(
-                new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
-                    @Override
-                    protected void showPopupContainerForIcon(BubbleTextView originalIcon) {
-                        showForIcon(originalIcon);
-                    }
-                });
         // TODO (b/198438631): configure for taskbar/context
         container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
         mControllers.taskbarDragController.addDragListener(container);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index d09f74c..e2c71bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.InsetsFrameProvider.SOURCE_DISPLAY;
 import static android.view.WindowInsets.Type.mandatorySystemGestures;
 import static android.view.WindowInsets.Type.navigationBars;
@@ -52,6 +53,10 @@
     // TaskbarManager#onNavButtonsDarkIntensityChanged()
     public float navButtonsDarkIntensity;
 
+    // TaskbarManager#onNavigationBarLumaSamplingEnabled()
+    public int mLumaSamplingDisplayId = DEFAULT_DISPLAY;
+    public boolean mIsLumaSamplingEnabled = true;
+
     public boolean setupUIVisible = false;
 
     public boolean allAppsVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
index bfbecf3..25db960 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DEEP_SHORTCUTS;
-import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.SHORTCUTS_AND_NOTIFICATIONS;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
@@ -36,7 +35,6 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.util.ShortcutUtil;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.LogUtils;
@@ -63,8 +61,6 @@
 
         mActions.put(DEEP_SHORTCUTS, new LauncherAction(DEEP_SHORTCUTS,
                 R.string.action_deep_shortcut, KeyEvent.KEYCODE_S));
-        mActions.put(SHORTCUTS_AND_NOTIFICATIONS, new LauncherAction(DEEP_SHORTCUTS,
-                R.string.shortcuts_menu_with_notifications_description, KeyEvent.KEYCODE_S));
         mActions.put(MOVE_TO_TOP_OR_LEFT, new LauncherAction(
                 MOVE_TO_TOP_OR_LEFT, R.string.move_drop_target_top_or_left, KeyEvent.KEYCODE_L));
         mActions.put(MOVE_TO_BOTTOM_OR_RIGHT, new LauncherAction(
@@ -76,8 +72,7 @@
     @Override
     protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
         if (ShortcutUtil.supportsShortcuts(item)) {
-            out.add(mActions.get(NotificationListener.getInstanceIfConnected() != null
-                    ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
+            out.add(mActions.get(DEEP_SHORTCUTS));
         }
         out.add(mActions.get(MOVE_TO_TOP_OR_LEFT));
         out.add(mActions.get(MOVE_TO_BOTTOM_OR_RIGHT));
@@ -117,7 +112,7 @@
                         instanceIds.first);
             }
             return true;
-        } else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
+        } else if (action == DEEP_SHORTCUTS) {
             mContext.showPopupMenuForIcon((BubbleTextView) host);
 
             return true;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 9aaa80f..41c0586 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -21,6 +21,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.internal.jank.InteractionJankMonitor.Configuration;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
@@ -60,8 +61,10 @@
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
+import com.android.quickstep.LauncherActivityInterface;
 import com.android.quickstep.SystemUiProxy;
 
 import java.io.PrintWriter;
@@ -95,7 +98,7 @@
     private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
 
     // If we're in an app and any of these flags are enabled, taskbar should be stashed.
-    private static final int FLAGS_STASHED_IN_APP =  FLAG_STASHED_IN_APP_SYSUI
+    private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_SYSUI
             | FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_APP_IME
             | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN
             | FLAG_STASHED_IN_APP_AUTO;
@@ -117,8 +120,7 @@
      *
      * Use {@link #getStashDuration()} to query duration
      */
-    private static final long TASKBAR_STASH_DURATION =
-            InsetsController.ANIMATION_DURATION_RESIZE;
+    private static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
 
     /**
      * How long to stash/unstash transient taskbar.
@@ -196,6 +198,7 @@
      * by not scaling the height of the taskbar background.
      */
     private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {
             TRANSITION_DEFAULT,
@@ -203,7 +206,8 @@
             TRANSITION_HANDLE_FADE,
             TRANSITION_UNSTASH_SUW_MANUAL,
     })
-    private @interface StashAnimation {}
+    private @interface StashAnimation {
+    }
 
     private final TaskbarActivityContext mActivity;
     private final int mStashedHeight;
@@ -256,7 +260,7 @@
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
         mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
 
-        if (isPhoneMode()) {
+        if (mActivity.isPhoneMode()) {
             mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(
                     R.dimen.taskbar_phone_size);
             mStashedHeight = mActivity.getResources().getDimensionPixelSize(
@@ -310,13 +314,14 @@
         boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
         boolean isStashedInAppAuto =
                 isTransientTaskbar && !mTaskbarSharedState.getTaskbarWasPinned();
+
         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
             isStashedInAppAuto = isStashedInAppAuto && mTaskbarSharedState.taskbarWasStashedAuto;
         }
         updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isStashedInAppAuto);
         updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
         updateStateForFlag(FLAG_IN_SETUP, isInSetup);
-        updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode()
+        updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, mActivity.isPhoneMode()
                 && !mActivity.isThreeButtonNav());
         // For now, assume we're in an app, since LauncherTaskbarUIController won't be able to tell
         // us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
@@ -386,13 +391,6 @@
         return (hasAnyFlag(FLAG_IN_STASHED_LAUNCHER_STATE) && supportsVisualStashing());
     }
 
-    /**
-     * @return {@code true} if we're not on a large screen AND using gesture nav
-     */
-    private boolean isPhoneMode() {
-        return TaskbarManager.isPhoneMode(mActivity.getDeviceProfile());
-    }
-
     private boolean hasAnyFlag(int flagMask) {
         return hasAnyFlag(mState, flagMask);
     }
@@ -424,11 +422,12 @@
 
     /**
      * Returns the height that taskbar will inset when inside apps.
+     *
      * @see android.view.WindowInsets.Type#navigationBars()
      * @see android.view.WindowInsets.Type#systemBars()
      */
     public int getContentHeightToReportToApps() {
-        if ((isPhoneMode() && !mActivity.isThreeButtonNav())
+        if ((mActivity.isPhoneMode() && !mActivity.isThreeButtonNav())
                 || DisplayController.isTransientTaskbar(mActivity)) {
             return getStashedHeight();
         }
@@ -458,6 +457,7 @@
 
     /**
      * Returns the height that taskbar will inset when inside apps.
+     *
      * @see android.view.WindowInsets.Type#tappableElement()
      */
     public int getTappableHeightToReportToApps() {
@@ -479,20 +479,21 @@
 
     /**
      * Stash or unstashes the transient taskbar.
-     * @param stash whether transient taskbar should be stashed.
+     *
+     * @param stash               whether transient taskbar should be stashed.
      * @param shouldBubblesFollow whether bubbles should match taskbars behavior.
      */
-    public void updateAndAnimateTransientTaskbar(boolean stash,  boolean shouldBubblesFollow) {
+    public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) {
         if (!DisplayController.isTransientTaskbar(mActivity)) {
             return;
         }
 
         if (
                 stash
-                && !mControllers.taskbarAutohideSuspendController
-                .isSuspendedForTransientTaskbarInLauncher()
-                && mControllers.taskbarAutohideSuspendController
-                .isTransientTaskbarStashingSuspended()) {
+                        && !mControllers.taskbarAutohideSuspendController
+                        .isSuspendedForTransientTaskbarInLauncher()
+                        && mControllers.taskbarAutohideSuspendController
+                        .isTransientTaskbarStashingSuspended()) {
             // Avoid stashing if autohide is currently suspended.
             return;
         }
@@ -554,7 +555,8 @@
         createAnimToIsStashed(
                 /* isStashed= */ false,
                 placeholderDuration,
-                TRANSITION_UNSTASH_SUW_MANUAL);
+                TRANSITION_UNSTASH_SUW_MANUAL,
+                /* jankTag= */ "SUW_MANUAL");
         animation.addListener(AnimatorListeners.forEndCallback(
                 () -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false)));
         animation.play(mAnimator);
@@ -562,12 +564,14 @@
 
     /**
      * Create a stash animation and save to {@link #mAnimator}.
-     * @param isStashed whether it's a stash animation or an unstash animation
-     * @param duration duration of the animation
+     *
+     * @param isStashed     whether it's a stash animation or an unstash animation
+     * @param duration      duration of the animation
      * @param animationType what transition type to play.
+     * @param jankTag       tag to be used in jank monitor trace.
      */
     private void createAnimToIsStashed(boolean isStashed, long duration,
-            @StashAnimation int animationType) {
+            @StashAnimation int animationType, String jankTag) {
         if (animationType == TRANSITION_UNSTASH_SUW_MANUAL && isStashed) {
             // The STASH_ANIMATION_SUW_MANUAL must only be used during an unstash animation.
             Log.e(TAG, "Illegal arguments:Using TRANSITION_UNSTASH_SUW_MANUAL to stash taskbar");
@@ -577,9 +581,10 @@
             mAnimator.cancel();
         }
         mAnimator = new AnimatorSet();
-        addJankMonitorListener(mAnimator, /* appearing= */ !mIsStashed);
+        addJankMonitorListener(
+                mAnimator, /* expanding= */ !isStashed, /* tag= */ jankTag);
         boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
-        final float stashTranslation = isPhoneMode() || isTransientTaskbar
+        final float stashTranslation = mActivity.isPhoneMode() || isTransientTaskbar
                 ? 0
                 : (mUnstashedHeight - mStashedHeight);
 
@@ -593,10 +598,12 @@
                             ? stashTranslation : 0)
                     .setDuration(duration));
             mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
-                    hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
+                    (hasAnyFlag(FLAG_STASHED_IN_APP_IME) && isStashed) ? 0 : 1).setDuration(
+                    duration));
             mAnimator.addListener(AnimatorListeners.forEndCallback(() -> {
                 mAnimator = null;
                 mIsStashed = isStashed;
+                onIsStashedChanged(mIsStashed);
             }));
             return;
         }
@@ -651,7 +658,7 @@
 
             firstHalfAnimatorSet.playTogether(
                     mIconAlphaForStash.animateToValue(0),
-                    mIconScaleForStash.animateToValue(isPhoneMode() ?
+                    mIconScaleForStash.animateToValue(mActivity.isPhoneMode() ?
                             0 : STASHED_TASKBAR_SCALE)
             );
             secondHalfAnimatorSet.playTogether(
@@ -662,7 +669,7 @@
                 fullLengthAnimatorSet.setInterpolator(INSTANT);
                 firstHalfAnimatorSet.setInterpolator(INSTANT);
             }
-        } else  {
+        } else {
             firstHalfDurationScale = 0.5f;
             secondHalfDurationScale = 0.75f;
 
@@ -802,14 +809,25 @@
         as.play(a);
     }
 
-    private void addJankMonitorListener(AnimatorSet animator, boolean expanding) {
+    private void addJankMonitorListener(
+            AnimatorSet animator, boolean expanding, String tag) {
         View v = mControllers.taskbarActivityContext.getDragLayer();
+        if (!v.isAttachedToWindow()) {
+            // If the task bar drag layer is not attached to window, we don't need to monitor jank
+            // (actually we can't pass in an unattached view either).
+            return;
+        }
         int action = expanding ? InteractionJankMonitor.CUJ_TASKBAR_EXPAND :
                 InteractionJankMonitor.CUJ_TASKBAR_COLLAPSE;
         animator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(@NonNull Animator animation) {
-                InteractionJankMonitor.getInstance().begin(v, action);
+                final Configuration.Builder builder =
+                        Configuration.Builder.withView(action, v);
+                if (tag != null) {
+                    builder.setTag(tag);
+                }
+                InteractionJankMonitor.getInstance().begin(builder);
             }
 
             @Override
@@ -832,13 +850,14 @@
             return;
         }
         mTaskbarStashedHandleHintScale.animateToValue(
-                animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1)
+                        animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1)
                 .setDuration(TASKBAR_HINT_STASH_DURATION).start();
     }
 
     private void onIsStashedChanged(boolean isStashed) {
         mControllers.runAfterInit(() -> {
-            mControllers.stashedHandleViewController.onIsStashedChanged(isStashed);
+            mControllers.stashedHandleViewController.onIsStashedChanged(
+                    isStashed && supportsVisualStashing());
             mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
         });
     }
@@ -872,18 +891,16 @@
     }
 
     /**
-     * Should be called when a system gesture starts and settles, so we can defer updating
-     * FLAG_STASHED_IN_APP_IME until after the gesture transition completes.
+     * Should be called when a system gesture starts and settles, so we can remove
+     * FLAG_STASHED_IN_APP_IME while the gesture is in progress.
      */
     public void setSystemGestureInProgress(boolean inProgress) {
         mIsSystemGestureInProgress = inProgress;
-        if (mIsSystemGestureInProgress) {
-            return;
-        }
+        setStashedImeState();
+    }
 
-        // Only update the following flags when system gesture is not in progress.
+    private void setStashedImeState() {
         boolean shouldStashForIme = shouldStashForIme();
-        updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
         if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
             updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme);
             applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
@@ -893,6 +910,13 @@
     }
 
     /**
+     * Should be called when Ime inset is changed to determine if taskbar should be stashed
+     */
+    public void onImeInsetChanged() {
+        setStashedImeState();
+    }
+
+    /**
      * When hiding the IME, delay the unstash animation to align with the end of the transition.
      */
     private long getTaskbarStashStartDelayForIme() {
@@ -923,12 +947,9 @@
                 && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY);
         updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked);
 
-        // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
         mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
         mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
-
-        if (!mIsSystemGestureInProgress) {
-            updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme());
+        if (updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme())) {
             animDuration = TASKBAR_STASH_DURATION_FOR_IME;
             startDelay = getTaskbarStashStartDelayForIme();
         }
@@ -937,19 +958,43 @@
     }
 
     /**
-     * We stash when IME or IME switcher is showing AND NOT
-     *  * in small screen AND
-     *  * 3 button nav AND
-     *  * landscape (or seascape)
-     * We do not stash if taskbar is transient or hardware keyboard is active.
+     * We stash when IME or IME switcher is showing.
+     *
+     * <p>Do not stash if in small screen, with 3 button nav, and in landscape (or seascape).
+     * <p>Do not stash if taskbar is transient.
+     * <p>Do not stash if hardware keyboard is attached and taskbar is pinned and IME is docked.
+     * <p>Do not stash if a system gesture is started.
      */
     private boolean shouldStashForIme() {
-        if (DisplayController.isTransientTaskbar(mActivity) || mActivity.isHardwareKeyboard()) {
+        if (DisplayController.isTransientTaskbar(mActivity)) {
             return false;
         }
-        return (mIsImeShowing || mIsImeSwitcherShowing) &&
-                !(isPhoneMode() && mActivity.isThreeButtonNav()
-                        && mActivity.getDeviceProfile().isLandscape);
+        // Do not stash if in small screen, with 3 button nav, and in landscape.
+        if (mActivity.isPhoneMode() && mActivity.isThreeButtonNav()
+                && mActivity.getDeviceProfile().isLandscape) {
+            return false;
+        }
+
+        // Do not stash if pinned taskbar, hardware keyboard is attached and no IME is docked
+        if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
+                && !mActivity.isImeDocked()) {
+            return false;
+        }
+
+        // Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode
+        DesktopVisibilityController visibilityController =
+                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+        if (visibilityController != null && mActivity.isHardwareKeyboard()
+                && mActivity.isThreeButtonNav() && visibilityController.areDesktopTasksVisible()) {
+            return false;
+        }
+
+        // Do not stash if a gesture started.
+        if (mIsSystemGestureInProgress) {
+            return false;
+        }
+
+        return mIsImeShowing || mIsImeSwitcherShowing;
     }
 
     /**
@@ -957,20 +1002,24 @@
      *
      * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
      *
-     * @param flag The flag to update.
+     * @param flag    The flag to update.
      * @param enabled Whether to enable the flag: True will cause the task bar to be stashed /
      *                unstashed.
+     * @return Whether the flag state changed.
      */
-    public void updateStateForFlag(int flag, boolean enabled) {
+    public boolean updateStateForFlag(int flag, boolean enabled) {
+        int oldState = mState;
         if (enabled) {
             mState |= flag;
         } else {
             mState &= ~flag;
         }
+        return mState != oldState;
     }
 
     /**
      * Called after updateStateForFlag() and applyState() have been called.
+     *
      * @param changedFlags The flags that have changed.
      */
     private void onStateChangeApplied(int changedFlags) {
@@ -979,7 +1028,7 @@
         }
         if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAGS_IN_APP)) {
             notifyStashChange(/* visible */ hasAnyFlag(FLAGS_IN_APP),
-                            /* stashed */ isStashedInApp());
+                    /* stashed */ isStashedInApp());
             mControllers.taskbarAutohideSuspendController.updateFlag(
                     TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, !isInApp());
         }
@@ -1044,6 +1093,7 @@
 
     /**
      * Updates the status of the taskbar timeout.
+     *
      * @param isAutohideSuspended If true, cancels any existing timeout
      *                            If false, attempts to re/start the timeout
      */
@@ -1115,6 +1165,7 @@
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_AUTO, "FLAG_STASHED_IN_APP_AUTO");
         appendFlag(sj, flags, FLAG_STASHED_SYSUI, "FLAG_STASHED_SYSUI");
         appendFlag(sj, flags, FLAG_STASHED_DEVICE_LOCKED, "FLAG_STASHED_DEVICE_LOCKED");
+        appendFlag(sj, flags, FLAG_IN_OVERVIEW, "FLAG_IN_OVERVIEW");
         return sj.toString();
     }
 
@@ -1134,7 +1185,8 @@
         /**
          * Creates an animator (stored in mAnimator) which applies the latest state, potentially
          * creating a new animation (stored in mAnimator).
-         * @param flags The latest flags to apply (see the top of this file).
+         *
+         * @param flags    The latest flags to apply (see the top of this file).
          * @param duration The length of the animation.
          * @return mAnimator if mIsStashed changed, or {@code null} otherwise.
          */
@@ -1190,12 +1242,34 @@
                 mLastStartedTransitionType = animationType;
 
                 // This sets mAnimator.
-                createAnimToIsStashed(mIsStashed, duration, animationType);
+                createAnimToIsStashed(mIsStashed, duration, animationType,
+                        computeTaskbarJankMonitorTag(changedFlags));
                 return mAnimator;
             }
             return null;
         }
 
+        /** Calculates the tag for CUJ_TASKBAR_EXPAND and CUJ_TASKBAR_COLLAPSE jank traces. */
+        private String computeTaskbarJankMonitorTag(int changedFlags) {
+            if (hasAnyFlag(changedFlags, FLAG_IN_APP)) {
+                // moving in or out of the app
+                if (hasAnyFlag(FLAG_IN_APP)) {
+                    return "Home to App";
+                } else {
+                    return "App to Home";
+                }
+            }
+            if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_AUTO)) {
+                // stash and unstash with-in the app
+                if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)) {
+                    return "Stashed in app";
+                } else {
+                    return "Manually unstashed";
+                }
+            }
+            return "";
+        }
+
         private @StashAnimation int computeTransitionType(int changedFlags) {
 
             boolean hotseatHiddenDuringAppLaunch =
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 916b1e6..144c0c2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -53,6 +53,7 @@
 
     private boolean mHasSprungOnceThisGesture;
     private @Nullable ValueAnimator mSpringBounce;
+    private boolean mGestureInProgress;
     private boolean mGestureEnded;
     private boolean mAnimationToHomeRunning;
 
@@ -155,7 +156,12 @@
     /**
      * Returns an animation to reset the taskbar translation to {@code 0}.
      */
-    public ObjectAnimator createAnimToResetTranslation(long duration) {
+    public ValueAnimator createAnimToResetTranslation(long duration) {
+        if (mGestureInProgress) {
+            // Return an empty animator as the translation will reset itself after gesture ends.
+            return ValueAnimator.ofFloat(0).setDuration(duration);
+        }
+
         ObjectAnimator animator = mTranslationYForSwipe.animateToValue(0);
         animator.setInterpolator(Interpolators.LINEAR);
         animator.setDuration(duration);
@@ -192,6 +198,7 @@
             mAnimationToHomeRunning = false;
             cancelSpringIfExists();
             reset();
+            mGestureInProgress = true;
         }
         /**
          * Called when there is movement to move the taskbar.
@@ -215,6 +222,7 @@
                 mGestureEnded = true;
                 startSpring();
             }
+            mGestureInProgress = false;
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index df2a43b..2e78489 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -20,11 +20,13 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+import static com.android.quickstep.OverviewCommandHelper.TYPE_HIDE;
 
 import android.content.Intent;
 import android.graphics.drawable.BitmapDrawable;
 import android.view.MotionEvent;
 import android.view.View;
+import android.window.RemoteTransition;
 
 import androidx.annotation.CallSuper;
 import androidx.annotation.NonNull;
@@ -37,7 +39,9 @@
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -92,6 +96,7 @@
     public void onTaskbarIconLaunched(ItemInfo item) {
         // When launching from Taskbar, e.g. from Overview, set FLAG_IN_APP immediately instead of
         // waiting for onPause, to reduce potential visual noise during the app open transition.
+        if (mControllers.taskbarStashController == null) return;
         mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, true);
         mControllers.taskbarStashController.applyState();
     }
@@ -188,7 +193,12 @@
     }
 
     /** Returns {@code true} if Taskbar is currently within overview. */
-    protected boolean isInOverview() {
+    protected boolean isInOverviewUi() {
+        return false;
+    }
+
+    /** Returns {@code true} if Home All Apps available instead of Taskbar All Apps. */
+    protected boolean canToggleHomeAllApps() {
         return false;
     }
 
@@ -219,7 +229,7 @@
                 Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
                 false /* findExactPairMatch */,
                 foundTasks -> {
-                    @Nullable Task foundTask = foundTasks.get(0);
+                    @Nullable Task foundTask = foundTasks[0];
                     splitSelectSource.alreadyRunningTaskId = foundTask == null
                             ? INVALID_TASK_ID
                             : foundTask.key.id;
@@ -238,7 +248,7 @@
                 Collections.singletonList(info.getComponentKey()),
                 false /* findExactPairMatch */,
                 foundTasks -> {
-                    @Nullable Task foundTask = foundTasks.get(0);
+                    @Nullable Task foundTask = foundTasks[0];
                     if (foundTask != null) {
                         TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
                         // TODO (b/266482558): This additional null check is needed because there
@@ -258,7 +268,8 @@
                                     taskAttributes.getThumbnailView(),
                                     taskAttributes.getThumbnailView().getThumbnail(),
                                     null /* intent */,
-                                    null /* user */);
+                                    null /* user */,
+                                    info);
                             return;
                         }
                     }
@@ -271,7 +282,8 @@
                             startingView,
                             null /* thumbnail */,
                             intent,
-                            info.user);
+                            info.user,
+                            info);
                 }
         );
     }
@@ -302,7 +314,8 @@
     /**
      * Launches the given task in split-screen.
      */
-    public void launchSplitTasks(@NonNull GroupTask groupTask) { }
+    public void launchSplitTasks(
+            @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) { }
 
     /**
      * Returns the matching view (if any) in the taskbar.
@@ -355,4 +368,43 @@
 
     /** Adjusts the hotseat for the bubble bar. */
     public void adjustHotseatForBubbleBar(boolean isBubbleBarVisible) {}
+
+    @Nullable
+    protected TISBindHelper getTISBindHelper() {
+        return null;
+    }
+
+    /**
+     * Launches the focused task in the Keyboard Quick Switch view through the OverviewCommandHelper
+     * <p>
+     * Use this helper method when the focused task may be the overview task.
+     */
+    public void launchKeyboardFocusedTask() {
+        TISBindHelper tisBindHelper = getTISBindHelper();
+        if (tisBindHelper == null) {
+            return;
+        }
+        OverviewCommandHelper overviewCommandHelper = tisBindHelper.getOverviewCommandHelper();
+        if (overviewCommandHelper == null) {
+            return;
+        }
+        overviewCommandHelper.addCommand(TYPE_HIDE);
+    }
+
+    /**
+     * Adjusts the taskbar based on the visibility of the launcher.
+     * @param isVisible True if launcher is visible, false otherwise.
+     */
+    public void onLauncherVisibilityChanged(boolean isVisible) {
+        mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, !isVisible);
+        mControllers.taskbarStashController.applyState();
+    }
+
+    /**
+     * Request for UI controller to ignore animations for the next callback for the end of recents
+     * animation
+     */
+    public void setSkipNextRecentsAnimEnd() {
+        // Overridden
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 2ab0066..effef3c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -18,6 +18,7 @@
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
@@ -31,6 +32,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.util.AttributeSet;
+import android.view.DisplayCutout;
 import android.view.InputDevice;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -51,7 +53,9 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.ThemedIconDrawable;
+import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -59,7 +63,6 @@
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.DoubleShadowBubbleTextView;
 import com.android.launcher3.views.IconButtonView;
 
 import java.util.function.Predicate;
@@ -84,7 +87,7 @@
     private final TaskbarActivityContext mActivityContext;
 
     // Initialized in init.
-    private TaskbarViewController.TaskbarViewCallbacks mControllerCallbacks;
+    private TaskbarViewCallbacks mControllerCallbacks;
     private View.OnClickListener mIconClickListener;
     private View.OnLongClickListener mIconLongClickListener;
 
@@ -123,7 +126,7 @@
         mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
         Resources resources = getResources();
         boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
-                && !TaskbarManager.isPhoneMode(mActivityContext.getDeviceProfile());
+                && !mActivityContext.isPhoneMode();
         mIsRtl = Utilities.isRtl(resources);
         mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width);
 
@@ -132,7 +135,7 @@
 
         int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
         int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
-        if (enableTaskbarPinning()) {
+        if (enableTaskbarPinning() && !mActivityContext.isThreeButtonNav()) {
             DeviceProfile deviceProfile = mActivityContext.getTransientTaskbarDeviceProfile();
             actualIconSize = deviceProfile.taskbarIconSize;
         }
@@ -257,7 +260,7 @@
         return mIconTouchSize;
     }
 
-    protected void init(TaskbarViewController.TaskbarViewCallbacks callbacks) {
+    protected void init(TaskbarViewCallbacks callbacks) {
         // set taskbar pane title so that accessibility service know it window and focuses.
         setAccessibilityPaneTitle(getContext().getString(R.string.taskbar_a11y_title));
         mControllerCallbacks = callbacks;
@@ -266,8 +269,12 @@
 
         if (mAllAppsButton != null) {
             mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener());
+            mAllAppsButton.setOnLongClickListener(
+                    mControllerCallbacks.getAllAppsButtonLongClickListener());
+            mAllAppsButton.setHapticFeedbackEnabled(
+                    mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
         }
-        if (mTaskbarDivider != null) {
+        if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
             mTaskbarDivider.setOnLongClickListener(
                     mControllerCallbacks.getTaskbarDividerLongClickListener());
             mTaskbarDivider.setOnTouchListener(
@@ -279,7 +286,7 @@
         removeView(view);
         view.setOnClickListener(null);
         view.setOnLongClickListener(null);
-        if (!(view.getTag() instanceof FolderInfo)) {
+        if (!(view.getTag() instanceof CollectionInfo)) {
             mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
         }
         view.setTag(null);
@@ -313,8 +320,8 @@
             boolean isCollection = false;
             if (hotseatItemInfo.isPredictedItem()) {
                 expectedLayoutResId = R.layout.taskbar_predicted_app_icon;
-            } else if (hotseatItemInfo instanceof FolderInfo fi) {
-                expectedLayoutResId = fi.itemType == ITEM_TYPE_APP_PAIR
+            } else if (hotseatItemInfo instanceof CollectionInfo ci) {
+                expectedLayoutResId = ci.itemType == ITEM_TYPE_APP_PAIR
                         ? R.layout.app_pair_icon
                         : R.layout.folder_icon;
                 isCollection = true;
@@ -342,16 +349,18 @@
 
             if (hotseatView == null) {
                 if (isCollection) {
-                    FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
+                    CollectionInfo collectionInfo = (CollectionInfo) hotseatItemInfo;
                     switch (hotseatItemInfo.itemType) {
                         case ITEM_TYPE_FOLDER:
                             hotseatView = FolderIcon.inflateFolderAndIcon(
-                                    expectedLayoutResId, mActivityContext, this, folderInfo);
+                                    expectedLayoutResId, mActivityContext, this,
+                                    (FolderInfo) collectionInfo);
                             ((FolderIcon) hotseatView).setTextVisible(false);
                             break;
                         case ITEM_TYPE_APP_PAIR:
                             hotseatView = AppPairIcon.inflateIcon(
-                                    expectedLayoutResId, mActivityContext, this, folderInfo);
+                                    expectedLayoutResId, mActivityContext, this,
+                                    (AppPairInfo) collectionInfo, DISPLAY_TASKBAR);
                             ((AppPairIcon) hotseatView).setTextVisible(false);
                             break;
                         default:
@@ -405,21 +414,6 @@
     }
 
     /**
-     * Traverse all the child views and change the background of themeIcons
-     **/
-    public void setThemedIconsBackgroundColor(int color) {
-        for (View icon : getIconViews()) {
-            if (icon instanceof DoubleShadowBubbleTextView) {
-                DoubleShadowBubbleTextView textView = ((DoubleShadowBubbleTextView) icon);
-                if (textView.getIcon() != null
-                        && textView.getIcon() instanceof ThemedIconDrawable) {
-                    ((ThemedIconDrawable) textView.getIcon()).changeBackgroundColor(color);
-                }
-            }
-        }
-    }
-
-    /**
      * Sets OnClickListener and OnLongClickListener for the given view.
      */
     public void setClickAndLongClickListenersForIcon(View icon) {
@@ -479,6 +473,29 @@
             iconEnd = centerAlignIconEnd + offset;
         }
 
+        // Currently, we support only one device with display cutout and we only are concern about
+        // it when the bottom rect is present and non empty
+        DisplayCutout displayCutout = getDisplay().getCutout();
+        if (displayCutout != null && !displayCutout.getBoundingRectBottom().isEmpty()) {
+            Rect cutoutBottomRect = displayCutout.getBoundingRectBottom();
+            // when cutout present at the bottom of screen align taskbar icons to cutout offset
+            // if taskbar icon overlaps with cutout
+            int taskbarIconLeftBound = iconEnd - spaceNeeded;
+            int taskbarIconRightBound = iconEnd;
+
+            boolean doesTaskbarIconsOverlapWithCutout =
+                    taskbarIconLeftBound <= cutoutBottomRect.centerX()
+                            && cutoutBottomRect.centerX() <= taskbarIconRightBound;
+
+            if (doesTaskbarIconsOverlapWithCutout) {
+                if (!layoutRtl) {
+                    iconEnd = spaceNeeded + cutoutBottomRect.width();
+                } else {
+                    iconEnd = right - cutoutBottomRect.width();
+                }
+            }
+        }
+
         sTmpRect.set(mIconLayoutBounds);
 
         // Layout the children
@@ -618,9 +635,11 @@
         super.onDraw(canvas);
         if (mLeaveBehindFolderIcon != null) {
             canvas.save();
-            canvas.translate(mLeaveBehindFolderIcon.getLeft(), mLeaveBehindFolderIcon.getTop());
-            mLeaveBehindFolderIcon.getFolderBackground().drawLeaveBehind(canvas,
-                    mFolderLeaveBehindColor);
+            canvas.translate(
+                    mLeaveBehindFolderIcon.getLeft() + mLeaveBehindFolderIcon.getTranslationX(),
+                    mLeaveBehindFolderIcon.getTop());
+            PreviewBackground previewBackground = mLeaveBehindFolderIcon.getFolderBackground();
+            previewBackground.drawLeaveBehind(canvas, mFolderLeaveBehindColor);
             canvas.restore();
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
new file mode 100644
index 0000000..c841cac
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
+
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.jank.Cuj;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+
+/**
+ * Callbacks for {@link TaskbarView} to interact with its controller.
+ */
+public class TaskbarViewCallbacks {
+
+    private final TaskbarActivityContext mActivity;
+    private final TaskbarControllers mControllers;
+    private final TaskbarView mTaskbarView;
+
+    public TaskbarViewCallbacks(TaskbarActivityContext activity, TaskbarControllers controllers,
+            TaskbarView taskbarView) {
+        mActivity = activity;
+        mControllers = controllers;
+        mTaskbarView = taskbarView;
+    }
+
+    public View.OnClickListener getIconOnClickListener() {
+        return mActivity.getItemOnClickListener();
+    }
+
+    public View.OnClickListener getAllAppsButtonClickListener() {
+        return v -> {
+            InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
+                    /* tag= */ "TASKBAR_BUTTON");
+            mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
+            mControllers.taskbarAllAppsController.toggle();
+        };
+    }
+
+    public View.OnLongClickListener getAllAppsButtonLongClickListener() {
+        return v -> {
+            mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
+            return true;
+        };
+    }
+
+    public boolean isAllAppsButtonHapticFeedbackEnabled() {
+        return false;
+    }
+
+    public View.OnLongClickListener getTaskbarDividerLongClickListener() {
+        return v -> {
+            mControllers.taskbarPinningController.showPinningView(v);
+            return true;
+        };
+    }
+
+    public View.OnTouchListener getTaskbarDividerRightClickListener() {
+        return (v, event) -> {
+            if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                    && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
+                mControllers.taskbarPinningController.showPinningView(v);
+                return true;
+            }
+            return false;
+        };
+    }
+
+    public View.OnLongClickListener getIconOnLongClickListener() {
+        return mControllers.taskbarDragController::startDragOnLongClick;
+    }
+
+    /** Gets the hover listener for the provided icon view. */
+    public View.OnHoverListener getIconOnHoverListener(View icon) {
+        return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
+    }
+
+    /**
+     * Notifies launcher to update icon alignment.
+     */
+    public void notifyIconLayoutBoundsChanged() {
+        mControllers.uiController.onIconLayoutBoundsChanged();
+    }
+
+    /**
+     * Notifies the taskbar scrim when the visibility of taskbar changes.
+     */
+    public void notifyVisibilityChanged() {
+        mControllers.taskbarScrimViewController.onTaskbarVisibilityChanged(
+                mTaskbarView.getVisibility());
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt
new file mode 100644
index 0000000..ba0f5a0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.Context
+import com.android.launcher3.R
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.util.ResourceBasedOverride.Overrides
+
+/** Creates [TaskbarViewCallbacks] instances. */
+open class TaskbarViewCallbacksFactory : ResourceBasedOverride {
+
+    open fun create(
+        activity: TaskbarActivityContext,
+        controllers: TaskbarControllers,
+        taskbarView: TaskbarView,
+    ): TaskbarViewCallbacks = TaskbarViewCallbacks(activity, controllers, taskbarView)
+
+    companion object {
+        @JvmStatic
+        fun newInstance(context: Context): TaskbarViewCallbacksFactory {
+            return Overrides.getObject(
+                TaskbarViewCallbacksFactory::class.java,
+                context,
+                R.string.taskbar_view_callbacks_factory_class,
+            )
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index c0cbd45..5d0eac3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -26,11 +26,8 @@
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
-import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
-import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
@@ -43,13 +40,11 @@
 import android.annotation.NonNull;
 import android.graphics.Rect;
 import android.util.Log;
-import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.animation.Interpolator;
 
 import androidx.annotation.Nullable;
-import androidx.core.graphics.ColorUtils;
 import androidx.core.view.OneShotPreDrawListener;
 
 import com.android.app.animation.Interpolators;
@@ -66,7 +61,6 @@
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.icons.ThemedIconDrawable;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -97,8 +91,6 @@
     public static final int ALPHA_INDEX_SMALL_SCREEN = 6;
     private static final int NUM_ALPHA_CHANNELS = 7;
 
-    private static final float TASKBAR_DARK_THEME_ICONS_BACKGROUND_LUMINANCE = 0.30f;
-
     private final TaskbarActivityContext mActivity;
     private final TaskbarView mTaskbarView;
     private final MultiValueAlpha mTaskbarIconAlpha;
@@ -129,12 +121,6 @@
 
     private int mTaskbarBottomMargin;
     private final int mStashedHandleHeight;
-    private final int mLauncherThemedIconsBackgroundColor;
-    private final int mTaskbarThemedIconsBackgroundColor;
-
-    /** Progress from {@code 0} for Launcher's color to {@code 1} for Taskbar's color. */
-    private final AnimatedFloat mThemedIconsBackgroundProgress = new AnimatedFloat(
-            this::updateIconsBackground);
 
     private final TaskbarModelCallbacks mModelCallbacks;
 
@@ -161,6 +147,8 @@
     private final int mTransientIconSize;
     private final int mPersistentIconSize;
 
+    private final float mTaskbarLeftRightMargin;
+
     public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
         mActivity = activity;
         mTransientTaskbarDp = mActivity.getTransientTaskbarDeviceProfile();
@@ -175,23 +163,18 @@
         mTaskbarBottomMargin = activity.getDeviceProfile().taskbarBottomMargin;
         mStashedHandleHeight = activity.getResources()
                 .getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height);
-        mLauncherThemedIconsBackgroundColor = ThemedIconDrawable.getColors(mActivity)[0];
-        if (!Utilities.isDarkTheme(mActivity)) {
-            mTaskbarThemedIconsBackgroundColor = mLauncherThemedIconsBackgroundColor;
-        } else {
-            // Increase luminance for dark themed icons given they are on a dark Taskbar background.
-            float[] colorHSL = new float[3];
-            ColorUtils.colorToHSL(mLauncherThemedIconsBackgroundColor, colorHSL);
-            colorHSL[2] = TASKBAR_DARK_THEME_ICONS_BACKGROUND_LUMINANCE;
-            mTaskbarThemedIconsBackgroundColor = ColorUtils.HSLToColor(colorHSL);
-        }
+
         mIsRtl = Utilities.isRtl(mTaskbarView.getResources());
+        mTaskbarLeftRightMargin = mActivity.getResources().getDimensionPixelSize(
+                R.dimen.transient_taskbar_padding);
+
     }
 
     public void init(TaskbarControllers controllers) {
         mControllers = controllers;
-        mTaskbarView.init(new TaskbarViewCallbacks());
-        mTaskbarView.getLayoutParams().height = isPhoneMode(mActivity.getDeviceProfile())
+        mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create(
+                mActivity, mControllers, mTaskbarView));
+        mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode()
                 ? mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_phone_size)
                 : mActivity.getDeviceProfile().taskbarHeight;
 
@@ -219,7 +202,7 @@
             // This gets modified in NavbarButtonsViewController, but the initial value it reads
             // may be incorrect since it's state gets destroyed on taskbar recreate, so reset here
             mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
-                    .animateToValue(isPhoneButtonNavMode(mActivity) ? 0 : 1).start();
+                    .animateToValue(mActivity.isPhoneButtonNavMode() ? 0 : 1).start();
         }
         if (enableTaskbarPinning()) {
             mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
@@ -354,11 +337,6 @@
     private void updateTaskbarIconTranslationXForPinning() {
         View[] iconViews = mTaskbarView.getIconViews();
         float scale = mTaskbarIconTranslationXForPinning.value;
-        float taskbarCenterX =
-                mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
-
-        float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
-
         float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
                 mTaskbarView.getAllAppsButtonTranslationXOffset(true));
         float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
@@ -371,6 +349,17 @@
             allAppIconTranslateRange *= -1;
         }
 
+        if (mActivity.isThreeButtonNav()) {
+            ((IconButtonView) mTaskbarView.getAllAppsButtonView())
+                    .setTranslationXForTaskbarAllAppsIcon(allAppIconTranslateRange);
+            return;
+        }
+
+        float taskbarCenterX =
+                mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
+
+        float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
+
         float halfIconCount = iconViews.length / 2.0f;
         for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
             View iconView = iconViews[iconIndex];
@@ -393,6 +382,26 @@
         }
     }
 
+    /**
+     * Calculates visual taskbar view width.
+     */
+    public float getCurrentVisualTaskbarWidth() {
+        if (mTaskbarView.getIconViews().length == 0) {
+            return 0;
+        }
+
+        View[] iconViews = mTaskbarView.getIconViews();
+
+        int leftIndex = mActivity.getDeviceProfile().isQsbInline && !mIsRtl ? 1 : 0;
+        int rightIndex = mActivity.getDeviceProfile().isQsbInline && mIsRtl
+                ? iconViews.length - 2
+                : iconViews.length - 1;
+
+        float left = iconViews[leftIndex].getX();
+        float right = iconViews[rightIndex].getRight() + iconViews[rightIndex].getTranslationX();
+
+        return right - left + (2 * mTaskbarLeftRightMargin);
+    }
 
     /**
      * Sets the translation of the TaskbarView during the swipe up gesture.
@@ -448,18 +457,6 @@
         return taskbarIconTranslationYForPinningValue;
     }
 
-    /**
-     * Updates the Taskbar's themed icons background according to the progress between in-app/home.
-     */
-    protected void updateIconsBackground() {
-        mTaskbarView.setThemedIconsBackgroundColor(
-                ColorUtils.blendARGB(
-                        mLauncherThemedIconsBackgroundColor,
-                        mTaskbarThemedIconsBackgroundColor,
-                        mThemedIconsBackgroundProgress.value
-                ));
-    }
-
     private ValueAnimator createRevealAnimForView(View view, boolean isStashed, float newWidth,
             boolean isQsb, boolean dispatchOnAnimationStart) {
         Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
@@ -506,6 +503,10 @@
         return reveal;
     }
 
+    public View getTaskbarDividerView() {
+        return mTaskbarView.getTaskbarDividerView();
+    }
+
     /**
      * Defers any updates to the UI for the setup wizard animation.
      */
@@ -598,7 +599,7 @@
      *                       1 => fully aligned
      */
     public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
-        if (isPhoneMode(launcherDp)) {
+        if (mActivity.isPhoneMode()) {
             mIconAlignControllerLazy = null;
             return;
         }
@@ -653,13 +654,9 @@
         setter.setFloat(mTaskbarNavButtonTranslationY, VALUE, -offsetY, interpolator);
         setter.setFloat(mTaskbarNavButtonTranslationYForInAppDisplay, VALUE, offsetY, interpolator);
 
-        if (Utilities.isDarkTheme(mTaskbarView.getContext())) {
-            setter.addFloat(mThemedIconsBackgroundProgress, VALUE, 1f, 0f, LINEAR);
-        }
-
-        int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight();
+        int collapsedHeight = mActivity.getDefaultTaskbarWindowSize();
         int expandedHeight = Math.max(collapsedHeight, taskbarDp.taskbarHeight + offsetY);
-        setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
+        setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowSize(
                 anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
 
         mTaskbarBottomMargin = isTransientTaskbar
@@ -795,8 +792,16 @@
             // We only translate on rotation when icon is aligned with hotseat
             return;
         }
-        mActivity.setTaskbarWindowHeight(
-                deviceProfile.taskbarHeight + deviceProfile.getTaskbarOffsetY());
+        int taskbarWindowSize;
+        if (mActivity.isPhoneMode()) {
+            taskbarWindowSize = mActivity.getResources().getDimensionPixelSize(
+                    mActivity.isThreeButtonNav()
+                            ? R.dimen.taskbar_phone_size
+                            : R.dimen.taskbar_stashed_size);
+        } else {
+            taskbarWindowSize = deviceProfile.taskbarHeight + deviceProfile.getTaskbarOffsetY();
+        }
+        mActivity.setTaskbarWindowSize(taskbarWindowSize);
         mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
     }
 
@@ -814,8 +819,8 @@
      * 3) All Apps button
      */
     public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
-        Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
-        return mTaskbarView.getFirstMatch(matcher, folderMatcher);
+        Predicate<ItemInfo> collectionMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+        return mTaskbarView.getFirstMatch(matcher, collectionMatcher);
     }
 
     /**
@@ -856,66 +861,4 @@
         mModelCallbacks.updateRunningApps();
     }
 
-    /**
-     * Callbacks for {@link TaskbarView} to interact with its controller.
-     */
-    public class TaskbarViewCallbacks {
-        private final float mSquaredTouchSlop = Utilities.squaredTouchSlop(mActivity);
-
-        private float mDownX, mDownY;
-        private boolean mCanceledStashHint;
-
-        public View.OnClickListener getIconOnClickListener() {
-            return mActivity.getItemOnClickListener();
-        }
-
-        public View.OnClickListener getAllAppsButtonClickListener() {
-            return v -> {
-                mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
-                mControllers.taskbarAllAppsController.toggle();
-            };
-        }
-
-        public View.OnLongClickListener getTaskbarDividerLongClickListener() {
-            return v -> {
-                mControllers.taskbarPinningController.showPinningView(v);
-                return true;
-            };
-        }
-
-        public View.OnTouchListener getTaskbarDividerRightClickListener() {
-            return (v, event) -> {
-                if (event.isFromSource(InputDevice.SOURCE_MOUSE)
-                        && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
-                    mControllers.taskbarPinningController.showPinningView(v);
-                    return true;
-                }
-                return false;
-            };
-        }
-
-        public View.OnLongClickListener getIconOnLongClickListener() {
-            return mControllers.taskbarDragController::startDragOnLongClick;
-        }
-
-        /** Gets the hover listener for the provided icon view. */
-        public View.OnHoverListener getIconOnHoverListener(View icon) {
-            return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
-        }
-
-        /**
-         * Notifies launcher to update icon alignment.
-         */
-        public void notifyIconLayoutBoundsChanged() {
-            mControllers.uiController.onIconLayoutBoundsChanged();
-        }
-
-        /**
-         * Notifies the taskbar scrim when the visibility of taskbar changes.
-         */
-        public void notifyVisibilityChanged() {
-            mControllers.taskbarScrimViewController.onTaskbarVisibilityChanged(
-                    mTaskbarView.getVisibility());
-        }
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 964d329..8e05686 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar.allapps;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.Flags.enablePredictiveBackGesture;
 
 import android.animation.Animator;
 import android.content.Context;
@@ -95,7 +96,7 @@
         mAllAppsCallbacks.onAllAppsTransitionStart(true);
         if (!animate) {
             mAllAppsCallbacks.onAllAppsTransitionEnd(true);
-            mTranslationShift = TRANSLATION_SHIFT_OPENED;
+            setTranslationShift(TRANSLATION_SHIFT_OPENED);
             return;
         }
 
@@ -168,7 +169,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         mActivityContext.addOnDeviceProfileChangeListener(this);
-        if (FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) {
+        if (enablePredictiveBackGesture()) {
             mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(mViewOutlineProvider);
             mAppsView.getAppsRecyclerViewContainer().setClipToOutline(true);
             OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
@@ -183,7 +184,7 @@
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         mActivityContext.removeOnDeviceProfileChangeListener(this);
-        if (FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) {
+        if (enablePredictiveBackGesture()) {
             mAppsView.getAppsRecyclerViewContainer().setOutlineProvider(null);
             mAppsView.getAppsRecyclerViewContainer().setClipToOutline(false);
             OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
@@ -195,18 +196,17 @@
 
     @Override
     protected void dispatchDraw(Canvas canvas) {
-        mAppsView.drawOnScrimWithScale(canvas, mSlideInViewScale.value);
+        // We should call drawOnScrimWithBottomOffset() rather than drawOnScrimWithScale(). Because
+        // for taskbar all apps, the scrim view is a child view of AbstractSlideInView. Thus scaling
+        // down in AbstractSlideInView#onScaleProgressChanged() with SCALE_PROPERTY has already
+        // done the job - there is no need to re-apply scale effect here. But it also means we need
+        // to pass extra bottom offset to background scrim to fill the bottom gap during predictive
+        // back swipe.
+        mAppsView.drawOnScrimWithBottomOffset(canvas, getBottomOffsetPx());
         super.dispatchDraw(canvas);
     }
 
     @Override
-    protected void onScaleProgressChanged() {
-        super.onScaleProgressChanged();
-        mAppsView.setClipChildren(!mIsBackProgressing);
-        mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsBackProgressing);
-    }
-
-    @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         setTranslationShift(mTranslationShift);
@@ -252,9 +252,29 @@
         return getPopupContainer().isEventOverView(mAppsView.getVisibleContainerView(), ev);
     }
 
+    /**
+     * In taskbar all apps search mode, we should scale down content inside all apps, rather
+     * than the whole all apps bottom sheet, to indicate we will navigate back within the all apps.
+     */
+    @Override
+    public boolean shouldAnimateContentViewInBackSwipe() {
+        return mAllAppsCallbacks.canHandleSearchBackInvoked();
+    }
+
+    @Override
+    protected void onUserSwipeToDismissProgressChanged() {
+        super.onUserSwipeToDismissProgressChanged();
+        mAppsView.setClipChildren(!mIsDismissInProgress);
+        mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
+    }
+
     @Override
     public void onBackInvoked() {
-        if (!mAllAppsCallbacks.handleSearchBackInvoked()) {
+        if (mAllAppsCallbacks.handleSearchBackInvoked()) {
+            // We need to scale back taskbar all apps if we navigate back within search inside all
+            // apps
+            post(this::animateSwipeToDismissProgressToStart);
+        } else {
             super.onBackInvoked();
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index b1c5151..52f7176 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -20,6 +20,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.allapps.AllAppsTransitionListener;
 import com.android.launcher3.anim.PendingAnimation;
@@ -31,6 +32,7 @@
 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;
 
@@ -136,6 +138,14 @@
                     && mAppsView.getSearchUiManager().getEditText() != null) {
                 mAppsView.getSearchUiManager().getEditText().requestFocus();
             }
+            if (toAllApps) {
+                InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
+            }
+        }
+
+        /** Check if search session can handle back. This check doesn't perform any action. */
+        boolean canHandleSearchBackInvoked() {
+            return mSearchSessionController.canHandleBackInvoked();
         }
 
         /** Invoked on back press, returning {@code true} if the search session handled it. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 3d15fbd..4d0b376 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -49,6 +49,8 @@
     /** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */
     open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null
 
+    open fun canHandleBackInvoked(): Boolean = false
+
     open fun handleBackInvoked(): Boolean = false
 
     open fun onAllAppsAnimationPending(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 1e3f4f1..ec47c4f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -15,29 +15,31 @@
  */
 package com.android.launcher3.taskbar.bubbles
 
+import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.ColorFilter
 import android.graphics.Paint
+import android.graphics.PixelFormat
 import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
 import com.android.app.animation.Interpolators
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.Utilities.mapToRange
 import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.launcher3.taskbar.TaskbarActivityContext
-import com.android.wm.shell.common.TriangleShape
+import com.android.launcher3.popup.RoundedArrowDrawable
 
 /** Drawable for the background of the bubble bar. */
-class BubbleBarBackground(context: TaskbarActivityContext, private val backgroundHeight: Float) :
-    Drawable() {
+class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
 
     private val DARK_THEME_SHADOW_ALPHA = 51f
     private val LIGHT_THEME_SHADOW_ALPHA = 25f
 
     private val paint: Paint = Paint()
-    private val pointerSize: Float
+    private val pointerWidth: Float
+    private val pointerHeight: Float
+    private val pointerTipRadius: Float
+    private val pointerVisibleHeight: Float
 
     private val shadowAlpha: Float
     private var shadowBlur = 0f
@@ -45,11 +47,28 @@
 
     var arrowPositionX: Float = 0f
         private set
+
     private var showingArrow: Boolean = false
-    private var arrowDrawable: ShapeDrawable
+    private var arrowDrawable: RoundedArrowDrawable
 
     var width: Float = 0f
 
+    /**
+     * Set whether the drawable is anchored to the left or right edge of the container.
+     *
+     * When `anchorLeft` is set to `true`, drawable left edge aligns up with the container left
+     * edge. Drawable can be drawn outside container bounds on the right edge. When it is set to
+     * `false` (the default), drawable right edge aligns up with the container right edge. Drawable
+     * can be drawn outside container bounds on the left edge.
+     */
+    var anchorLeft: Boolean = false
+        set(value) {
+            if (field != value) {
+                field = value
+                invalidateSelf()
+            }
+        }
+
     init {
         paint.color = context.getColor(R.color.taskbar_background)
         paint.flags = Paint.ANTI_ALIAS_FLAG
@@ -58,7 +77,10 @@
         val res = context.resources
         shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
         keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
-        pointerSize = res.getDimension(R.dimen.bubblebar_pointer_size)
+        pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+        pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+        pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+        pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
 
         shadowAlpha =
             if (Utilities.isDarkTheme(context)) {
@@ -68,11 +90,14 @@
             }
 
         arrowDrawable =
-            ShapeDrawable(TriangleShape.create(pointerSize, pointerSize, /* pointUp= */ true))
-        arrowDrawable.setBounds(0, 0, pointerSize.toInt(), pointerSize.toInt())
-        arrowDrawable.paint.flags = Paint.ANTI_ALIAS_FLAG
-        arrowDrawable.paint.style = Paint.Style.FILL
-        arrowDrawable.paint.color = context.getColor(R.color.taskbar_background)
+            RoundedArrowDrawable.createVerticalRoundedArrow(
+                pointerWidth,
+                pointerHeight,
+                pointerTipRadius,
+                /* isPointingUp= */ true,
+                context.getColor(R.color.taskbar_background)
+            )
+        arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
     }
 
     fun showArrow(show: Boolean) {
@@ -97,7 +122,7 @@
             keyShadowDistance,
             setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
         )
-        arrowDrawable.paint.setShadowLayer(
+        arrowDrawable.setShadowLayer(
             shadowBlur,
             0f,
             keyShadowDistance,
@@ -106,11 +131,13 @@
 
         // Draw background.
         val radius = backgroundHeight / 2f
+        val left = if (anchorLeft) 0f else bounds.width().toFloat() - width
+        val right = if (anchorLeft) width else bounds.width().toFloat()
         canvas.drawRoundRect(
-            canvas.width.toFloat() - width,
-            0f,
-            canvas.width.toFloat(),
-            canvas.height.toFloat(),
+            left,
+            pointerVisibleHeight,
+            right,
+            bounds.height().toFloat(),
             radius,
             radius,
             paint
@@ -118,8 +145,8 @@
 
         if (showingArrow) {
             // Draw arrow.
-            val transX = arrowPositionX - pointerSize / 2f
-            canvas.translate(transX, -pointerSize)
+            val transX = arrowPositionX - pointerWidth / 2f
+            canvas.translate(transX, 0f)
             arrowDrawable.draw(canvas)
         }
 
@@ -127,11 +154,20 @@
     }
 
     override fun getOpacity(): Int {
-        return paint.alpha
+        return when (paint.alpha) {
+            255 -> PixelFormat.OPAQUE
+            0 -> PixelFormat.TRANSPARENT
+            else -> PixelFormat.TRANSLUCENT
+        }
     }
 
     override fun setAlpha(alpha: Int) {
         paint.alpha = alpha
+        arrowDrawable.alpha = alpha
+    }
+
+    override fun getAlpha(): Int {
+        return paint.alpha
     }
 
     override fun setColorFilter(colorFilter: ColorFilter?) {
@@ -139,6 +175,10 @@
     }
 
     fun setArrowAlpha(alpha: Int) {
-        arrowDrawable.paint.alpha = alpha
+        arrowDrawable.alpha = alpha
+    }
+
+    fun setHeight(newHeight: Float) {
+        backgroundHeight = newHeight
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 3fb7247..981c9f9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -46,6 +46,8 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -66,9 +68,12 @@
 import com.android.launcher3.icons.BubbleIconFactory;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors.SimpleThreadFactory;
 import com.android.quickstep.SystemUiProxy;
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.bubbles.IBubblesListener;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
 import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
 import com.android.wm.shell.common.bubbles.BubbleInfo;
 import com.android.wm.shell.common.bubbles.RemovedBubble;
@@ -98,8 +103,8 @@
      *
      * @see #onTaskbarRecreated()
      */
-    private static boolean sBubbleBarEnabled =
-            SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+    private static boolean sBubbleBarEnabled = Flags.enableBubbleBar()
+            || SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
 
     /** Whether showing bubbles in the launcher bubble bar is enabled. */
     public static boolean isBubbleBarEnabled() {
@@ -108,8 +113,10 @@
 
     /** Re-reads the value of the flag from SystemProperties when taskbar is recreated. */
     public static void onTaskbarRecreated() {
-        sBubbleBarEnabled = SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+        sBubbleBarEnabled = Flags.enableBubbleBar()
+                || SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
     }
+
     private static final int MASK_HIDE_BUBBLE_BAR = SYSUI_STATE_BOUNCER_SHOWING
             | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
             | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
@@ -144,17 +151,22 @@
     private BubbleStashController mBubbleStashController;
     private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
 
+    // Keep track of bubble bar bounds sent to shell to avoid sending duplicate updates
+    private final Rect mLastSentBubbleBarBounds = new Rect();
+
     /**
      * Similar to {@link BubbleBarUpdate} but rather than {@link BubbleInfo}s it uses
      * {@link BubbleBarBubble}s so that it can be used to update the views.
      */
     private static class BubbleBarViewUpdate {
+        final boolean initialState;
         boolean expandedChanged;
         boolean expanded;
         boolean shouldShowEducation;
         String selectedBubbleKey;
         String suppressedBubbleKey;
         String unsuppressedBubbleKey;
+        BubbleBarLocation bubbleBarLocation;
         List<RemovedBubble> removedBubbles;
         List<String> bubbleKeysInOrder;
 
@@ -164,12 +176,14 @@
         List<BubbleBarBubble> currentBubbles;
 
         BubbleBarViewUpdate(BubbleBarUpdate update) {
+            initialState = update.initialState;
             expandedChanged = update.expandedChanged;
             expanded = update.expanded;
             shouldShowEducation = update.shouldShowEducation;
             selectedBubbleKey = update.selectedBubbleKey;
             suppressedBubbleKey = update.suppressedBubbleKey;
             unsuppressedBubbleKey = update.unsupressedBubbleKey;
+            bubbleBarLocation = update.bubbleBarLocation;
             removedBubbles = update.removedBubbles;
             bubbleKeysInOrder = update.bubbleKeysInOrder;
         }
@@ -209,7 +223,8 @@
             mBubbleStashedHandleViewController.setHiddenForBubbles(
                     !sBubbleBarEnabled || mBubbles.isEmpty());
             mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
-                    key -> setSelectedBubble(mBubbles.get(key)));
+                    key -> setSelectedBubbleInternal(mBubbles.get(key)));
+            mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged);
         });
     }
 
@@ -226,7 +241,8 @@
                 // we're on the main executor now, so check that the overflow hasn't been created
                 // again to avoid races.
                 if (mOverflowBubble == null) {
-                    mBubbleBarViewController.addBubble(overflow);
+                    mBubbleBarViewController.addBubble(
+                            overflow, /* isExpanding= */ false, /* suppressAnimation= */ true);
                     mOverflowBubble = overflow;
                 }
             });
@@ -295,6 +311,13 @@
     private void applyViewChanges(BubbleBarViewUpdate update) {
         final boolean isCollapsed = (update.expandedChanged && !update.expanded)
                 || (!update.expandedChanged && !mBubbleBarViewController.isExpanded());
+        final boolean isExpanding = update.expandedChanged && update.expanded;
+        // don't animate bubbles if this is the initial state because we may be unfolding or
+        // enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g.
+        // the shade is open, or we're locked.
+        final boolean suppressAnimation =
+                update.initialState || mBubbleBarViewController.isHiddenForSysui();
+
         BubbleBarItem previouslySelectedBubble = mSelectedBubble;
         BubbleBarBubble bubbleToSelect = null;
         if (!update.removedBubbles.isEmpty()) {
@@ -311,7 +334,7 @@
         }
         if (update.addedBubble != null) {
             mBubbles.put(update.addedBubble.getKey(), update.addedBubble);
-            mBubbleBarViewController.addBubble(update.addedBubble);
+            mBubbleBarViewController.addBubble(update.addedBubble, isExpanding, suppressAnimation);
             if (isCollapsed) {
                 // If we're collapsed, the most recently added bubble will be selected.
                 bubbleToSelect = update.addedBubble;
@@ -324,7 +347,7 @@
                 BubbleBarBubble bubble = update.currentBubbles.get(i);
                 if (bubble != null) {
                     mBubbles.put(bubble.getKey(), bubble);
-                    mBubbleBarViewController.addBubble(bubble);
+                    mBubbleBarViewController.addBubble(bubble, isExpanding, suppressAnimation);
                     if (isCollapsed) {
                         // If we're collapsed, the most recently added bubble will be selected.
                         bubbleToSelect = bubble;
@@ -379,7 +402,7 @@
             }
         }
         if (bubbleToSelect != null) {
-            setSelectedBubble(bubbleToSelect);
+            setSelectedBubbleInternal(bubbleToSelect);
             if (previouslySelectedBubble == null) {
                 mBubbleStashController.animateToInitialState(update.expanded);
             }
@@ -394,6 +417,13 @@
                 Log.w(TAG, "expansion was changed but is the same");
             }
         }
+        if (update.bubbleBarLocation != null) {
+            if (update.bubbleBarLocation != mBubbleBarViewController.getBubbleBarLocation()) {
+                // Animate when receiving updates. Skip it if we received the initial state.
+                boolean animate = !update.initialState;
+                updateBubbleBarLocationInternal(update.bubbleBarLocation, animate);
+            }
+        }
     }
 
     /** Tells WMShell to show the currently selected bubble. */
@@ -408,8 +438,9 @@
                         info.getFlags() | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION);
                 mSelectedBubble.getView().updateDotVisibility(true /* animate */);
             }
-            mSystemUiProxy.showBubble(getSelectedBubbleKey(),
-                    getBubbleBarOffsetX(), getBubbleBarOffsetY());
+            Rect bounds = getExpandedBubbleBarDisplayBounds();
+            mLastSentBubbleBarBounds.set(bounds);
+            mSystemUiProxy.showBubble(getSelectedBubbleKey(), bounds);
         } else {
             Log.w(TAG, "Trying to show the selected bubble but it's null");
         }
@@ -418,7 +449,7 @@
     /** Updates the currently selected bubble for launcher views and tells WMShell to show it. */
     public void showAndSelectBubble(BubbleBarItem b) {
         if (DEBUG) Log.w(TAG, "showingSelectedBubble: " + b.getKey());
-        setSelectedBubble(b);
+        setSelectedBubbleInternal(b);
         showSelectedBubble();
     }
 
@@ -427,7 +458,7 @@
      * WMShell that the selection has changed, that should go through either
      * {@link #showSelectedBubble()} or {@link #showAndSelectBubble(BubbleBarItem)}.
      */
-    private void setSelectedBubble(BubbleBarItem b) {
+    private void setSelectedBubbleInternal(BubbleBarItem b) {
         if (!Objects.equals(b, mSelectedBubble)) {
             if (DEBUG) Log.w(TAG, "selectingBubble: " + b.getKey());
             mSelectedBubble = b;
@@ -446,6 +477,21 @@
         return null;
     }
 
+    /**
+     * Set a new bubble bar location.
+     * <p>
+     * Updates the value locally in Launcher and in WMShell.
+     */
+    public void updateBubbleBarLocation(BubbleBarLocation location) {
+        updateBubbleBarLocationInternal(location, false /* animate */);
+        mSystemUiProxy.setBubbleBarLocation(location);
+    }
+
+    private void updateBubbleBarLocationInternal(BubbleBarLocation location, boolean animate) {
+        mBubbleBarViewController.setBubbleBarLocation(location, animate);
+        mBubbleStashController.setBubbleBarLocation(location);
+    }
+
     //
     // Loading data for the bubbles
     //
@@ -577,12 +623,39 @@
         return mIconFactory.createBadgedIconBitmap(drawable).icon;
     }
 
-    private int getBubbleBarOffsetY() {
-        final int translation = (int) abs(mBubbleStashController.getBubbleBarTranslationY());
-        return translation + mBarView.getHeight();
+    private void onBubbleBarBoundsChanged(Rect newBounds) {
+        Rect displayBounds = convertToDisplayBounds(newBounds);
+        // Only send bounds over if they changed
+        if (!displayBounds.equals(mLastSentBubbleBarBounds)) {
+            mLastSentBubbleBarBounds.set(displayBounds);
+            mSystemUiProxy.setBubbleBarBounds(displayBounds);
+        }
     }
 
-    private int getBubbleBarOffsetX() {
-        return mBarView.getWidth() + mBarView.getHorizontalMargin();
+    /**
+     * Get bounds of the bubble bar as if it would be expanded.
+     * Calculates the bounds instead of retrieving current view location as the view may be
+     * animating.
+     */
+    private Rect getExpandedBubbleBarDisplayBounds() {
+        return convertToDisplayBounds(mBarView.getBubbleBarBounds());
+    }
+
+    private Rect convertToDisplayBounds(Rect currentBarBounds) {
+        Point displaySize = DisplayController.INSTANCE.get(mContext).getInfo().currentSize;
+        Rect displayBounds = new Rect();
+        // currentBarBounds is only useful for distance from left or right edge.
+        // It contains the current bounds, calculate the expanded bounds.
+        if (mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl())) {
+            displayBounds.left = currentBarBounds.left;
+            displayBounds.right = (int) (currentBarBounds.left + mBarView.expandedWidth());
+        } else {
+            displayBounds.left = (int) (currentBarBounds.right - mBarView.expandedWidth());
+            displayBounds.right = currentBarBounds.right;
+        }
+        final int translation = (int) abs(mBubbleStashController.getBubbleBarTranslationY());
+        displayBounds.top = displaySize.y - currentBarBounds.height() - translation;
+        displayBounds.bottom = displaySize.y - translation;
+        return displayBounds;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
new file mode 100644
index 0000000..8ed9949
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Point
+import android.graphics.RectF
+import android.view.Gravity.BOTTOM
+import android.view.Gravity.LEFT
+import android.view.Gravity.RIGHT
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.R
+import com.android.wm.shell.common.bubbles.BaseBubblePinController
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+
+/**
+ * Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar
+ */
+class BubbleBarPinController(
+    private val context: Context,
+    private val container: FrameLayout,
+    private val screenSizeProvider: () -> Point
+) : BaseBubblePinController() {
+
+    private lateinit var bubbleBarViewController: BubbleBarViewController
+    private lateinit var bubbleStashController: BubbleStashController
+    private var dropTargetView: View? = null
+
+    fun init(bubbleControllers: BubbleControllers) {
+        bubbleBarViewController = bubbleControllers.bubbleBarViewController
+        bubbleStashController = bubbleControllers.bubbleStashController
+    }
+
+    override fun getScreenCenterX(): Int {
+        return screenSizeProvider.invoke().x / 2
+    }
+
+    override fun getExclusionRect(): RectF {
+        val rect =
+            RectF(
+                0f,
+                0f,
+                context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width),
+                context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
+            )
+        val screenSize = screenSizeProvider.invoke()
+        val middleX = screenSize.x / 2
+        // Center it around the bottom center of the screen
+        rect.offsetTo(middleX - rect.width() / 2, screenSize.y - rect.height())
+        return rect
+    }
+
+    override fun createDropTargetView(): View {
+        return LayoutInflater.from(context)
+            .inflate(R.layout.bubble_bar_drop_target, container, false)
+            .also { view ->
+                dropTargetView = view
+                container.addView(view)
+            }
+    }
+
+    override fun getDropTargetView(): View? {
+        return dropTargetView
+    }
+
+    override fun removeDropTargetView(view: View) {
+        container.removeView(view)
+        dropTargetView = null
+    }
+
+    @SuppressLint("RtlHardcoded")
+    override fun updateLocation(location: BubbleBarLocation) {
+        val onLeft = location.isOnLeft(container.isLayoutRtl)
+
+        val bounds = bubbleBarViewController.bubbleBarBounds
+        val horizontalMargin = bubbleBarViewController.horizontalMargin
+        dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> {
+            width = bounds.width()
+            height = bounds.height()
+            gravity = BOTTOM or (if (onLeft) LEFT else RIGHT)
+            leftMargin = horizontalMargin
+            rightMargin = horizontalMargin
+            bottomMargin = -bubbleStashController.bubbleBarTranslationY.toInt()
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c482911..110c30f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -15,21 +15,33 @@
  */
 package com.android.launcher3.taskbar.bubbles;
 
+import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+
 import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.LayoutDirection;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.dynamicanimation.animation.SpringForce;
+
 import com.android.launcher3.R;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
 
 import java.util.List;
 import java.util.function.Consumer;
@@ -70,8 +82,22 @@
     private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
     private static final int WIDTH_ANIMATION_DURATION_MS = 200;
 
+    private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L;
+    private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L;
+    private static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L;
+    // During fade out animation we shift the bubble bar 1/80th of the screen width
+    private static final float FADE_OUT_ANIM_POSITION_SHIFT = 1 / 80f;
+
+    private static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L;
+    // Use STIFFNESS_MEDIUMLOW which is not defined in the API constants
+    private static final float FADE_IN_ANIM_POSITION_SPRING_STIFFNESS = 400f;
+    // During fade in animation we shift the bubble bar 1/60th of the screen width
+    private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
+
     private final BubbleBarBackground mBubbleBarBackground;
 
+    private boolean mIsAnimatingNewBubble = false;
+
     /**
      * The current bounds of all the bubble bar. Note that these bounds may not account for
      * translation. The bounds should be retrieved using {@link #getBubbleBarBounds()} which
@@ -80,17 +106,22 @@
     private final Rect mBubbleBarBounds = new Rect();
     // The amount the bubbles overlap when they are stacked in the bubble bar
     private final float mIconOverlapAmount;
-    // The spacing between the bubbles when they are expanded in the bubble bar
-    private final float mIconSpacing;
+    // The spacing between the bubbles when bubble bar is expanded
+    private final float mExpandedBarIconsSpacing;
+    // The spacing between the bubbles and the borders of the bubble bar
+    private float mBubbleBarPadding;
     // The size of a bubble in the bar
-    private final float mIconSize;
+    private float mIconSize;
     // The elevation of the bubbles within the bar
     private final float mBubbleElevation;
+    private final float mDragElevation;
+    private final int mPointerSize;
 
     // Whether the bar is expanded (i.e. the bubble activity is being displayed).
     private boolean mIsBarExpanded = false;
     // The currently selected bubble view.
     private BubbleView mSelectedBubbleView;
+    private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
     // The click listener when the bubble bar is collapsed.
     private View.OnClickListener mOnClickListener;
 
@@ -102,6 +133,9 @@
     // collapsed state and 1 to the fully expanded state.
     private final ValueAnimator mWidthAnimator = ValueAnimator.ofFloat(0, 1);
 
+    @Nullable
+    private Animator mBubbleBarLocationAnimator = null;
+
     // We don't reorder the bubbles when they are expanded as it could be jarring for the user
     // this runnable will be populated with any reordering of the bubbles that should be applied
     // once they are collapsed.
@@ -111,9 +145,15 @@
     @Nullable
     private Consumer<String> mUpdateSelectedBubbleAfterCollapse;
 
+    private boolean mDragging;
+
     @Nullable
     private BubbleView mDraggedBubbleView;
 
+    private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
+
+    private boolean mLocationChangePending;
+
     public BubbleBarView(Context context) {
         this(context, null);
     }
@@ -128,16 +168,21 @@
 
     public BubbleBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        TaskbarActivityContext activityContext = ActivityContext.lookupContext(context);
-
+        setAlpha(0);
+        setVisibility(INVISIBLE);
         mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
-        mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+        mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
         mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+        mExpandedBarIconsSpacing = getResources().getDimensionPixelSize(
+                R.dimen.bubblebar_expanded_icon_spacing);
         mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
+        mDragElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
+        mPointerSize = getResources()
+                .getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size);
+
         setClipToPadding(false);
 
-        mBubbleBarBackground = new BubbleBarBackground(activityContext,
-                getResources().getDimensionPixelSize(R.dimen.bubblebar_size));
+        mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarHeight());
         setBackgroundDrawable(mBubbleBarBackground);
 
         mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
@@ -178,11 +223,34 @@
         });
     }
 
+    /**
+     * Sets new icon size and spacing between icons and bubble bar borders.
+     *
+     * @param newIconSize new icon size
+     * @param spacing     spacing between icons and bubble bar borders.
+     */
+    // TODO(b/335575529): animate bubble bar icons size change
+    public void setIconSizeAndPadding(float newIconSize, float spacing) {
+        // TODO(b/335457839): handle new bubble animation during the size change
+        mBubbleBarPadding = spacing;
+        mIconSize = newIconSize;
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View childView = getChildAt(i);
+            FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
+            params.height = (int) mIconSize;
+            params.width = (int) mIconSize;
+            childView.setLayoutParams(params);
+        }
+        mBubbleBarBackground.setHeight(getBubbleBarHeight());
+        updateLayoutParams();
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         mBubbleBarBounds.left = left;
-        mBubbleBarBounds.top = top;
+        mBubbleBarBounds.top = top + mPointerSize;
         mBubbleBarBounds.right = right;
         mBubbleBarBounds.bottom = bottom;
 
@@ -195,11 +263,197 @@
         updateChildrenRenderNodeProperties();
     }
 
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        if (mBubbleBarLocation == BubbleBarLocation.DEFAULT
+                && mPreviousLayoutDirection != layoutDirection) {
+            Log.d(TAG, "BubbleBar RTL properties changed, new layoutDirection=" + layoutDirection
+                    + " previous layoutDirection=" + mPreviousLayoutDirection);
+            mPreviousLayoutDirection = layoutDirection;
+            onBubbleBarLocationChanged();
+        }
+    }
+
+    @SuppressLint("RtlHardcoded")
+    private void onBubbleBarLocationChanged() {
+        mLocationChangePending = false;
+        final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
+        mBubbleBarBackground.setAnchorLeft(onLeft);
+        mRelativePivotX = onLeft ? 0f : 1f;
+        if (getLayoutParams() instanceof LayoutParams lp) {
+            lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
+            setLayoutParams(lp);
+        }
+        invalidate();
+    }
+
+    /**
+     * @return current {@link BubbleBarLocation}
+     */
+    public BubbleBarLocation getBubbleBarLocation() {
+        return mBubbleBarLocation;
+    }
+
+    /**
+     * Update {@link BubbleBarLocation}
+     */
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
+        if (animate) {
+            animateToBubbleBarLocation(bubbleBarLocation);
+        } else {
+            setBubbleBarLocationInternal(bubbleBarLocation);
+        }
+    }
+
+    /**
+     * Set whether this view is being currently being dragged
+     */
+    public void setIsDragging(boolean dragging) {
+        if (mDragging == dragging) {
+            return;
+        }
+        mDragging = dragging;
+        setElevation(dragging ? mDragElevation : mBubbleElevation);
+        if (!dragging && mLocationChangePending) {
+            // During drag finish animation we may update the translation x value to shift the
+            // bubble to the new drop target. Clear the translation here.
+            setTranslationX(0f);
+            onBubbleBarLocationChanged();
+        }
+    }
+
+    /**
+     * Adjust resting position for the bubble bar while it is being dragged.
+     * <p>
+     * Bubble bar is laid out on left or right side of the screen. When it is being dragged to
+     * the opposite side, the resting position should be on that side. Calculate any additional
+     * translation that may be required to move the bubble bar to the new side.
+     *
+     * @param restingPosition relative resting position of the bubble bar from the laid out position
+     */
+    @SuppressLint("RtlHardcoded")
+    void adjustRelativeRestingPosition(PointF restingPosition) {
+        final boolean locationOnLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
+        // Bubble bar is placed left or right with gravity. Check where it is currently.
+        final int absoluteGravity = Gravity.getAbsoluteGravity(
+                ((LayoutParams) getLayoutParams()).gravity, getLayoutDirection());
+        final boolean gravityOnLeft =
+                (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT;
+
+        // Bubble bar is pinned to the same side per gravity and the desired location.
+        // Resting translation does not need to be adjusted.
+        if (locationOnLeft == gravityOnLeft) {
+            return;
+        }
+
+        // Bubble bar is laid out on left or right side of the screen. And the desired new
+        // location is on the other side. Calculate x translation value required to shift the
+        // bubble bar from one side to the other.
+        float x = getDistanceFromOtherSide();
+        if (locationOnLeft) {
+            // New location is on the left, shift left
+            // before -> |......ooo.| after -> |.ooo......|
+            restingPosition.x = -x;
+        } else {
+            // New location is on the right, shift right
+            // before -> |.ooo......| after -> |......ooo.|
+            restingPosition.x = x;
+        }
+    }
+
+    private float getDistanceFromOtherSide() {
+        // Calculate the shift needed to position the bubble bar on the other side
+        int displayWidth = getResources().getDisplayMetrics().widthPixels;
+        int margin = 0;
+        if (getLayoutParams() instanceof MarginLayoutParams lp) {
+            margin += lp.leftMargin;
+            margin += lp.rightMargin;
+        }
+        return (float) (displayWidth - getWidth() - margin);
+    }
+
+    private void setBubbleBarLocationInternal(BubbleBarLocation bubbleBarLocation) {
+        if (bubbleBarLocation != mBubbleBarLocation) {
+            mBubbleBarLocation = bubbleBarLocation;
+            if (mDragging) {
+                mLocationChangePending = true;
+            } else {
+                onBubbleBarLocationChanged();
+                invalidate();
+            }
+        }
+    }
+
+    private void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        if (bubbleBarLocation == mBubbleBarLocation) {
+            // nothing to do, already at expected location
+            return;
+        }
+        if (mBubbleBarLocationAnimator != null && mBubbleBarLocationAnimator.isRunning()) {
+            mBubbleBarLocationAnimator.cancel();
+        }
+
+        // Location animation uses two separate animators.
+        // First animator hides the bar.
+        // After it completes, location update is sent to layout the bar in the new location.
+        // Second animator is started to show the bar.
+        mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator();
+        mBubbleBarLocationAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Bubble bar is not visible, update the location
+                setBubbleBarLocationInternal(bubbleBarLocation);
+                // Animate it in
+                mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator();
+                mBubbleBarLocationAnimator.start();
+            }
+        });
+        mBubbleBarLocationAnimator.start();
+    }
+
+    private AnimatorSet getLocationUpdateFadeOutAnimator() {
+        final float shift =
+                getResources().getDisplayMetrics().widthPixels * FADE_OUT_ANIM_POSITION_SHIFT;
+        final float tx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+
+        ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X, tx)
+                .setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS);
+        positionAnim.setInterpolator(EMPHASIZED_ACCELERATE);
+
+        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 0f)
+                .setDuration(FADE_OUT_ANIM_ALPHA_DURATION_MS);
+        alphaAnim.setStartDelay(FADE_OUT_ANIM_ALPHA_DELAY_MS);
+
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(positionAnim, alphaAnim);
+        return animatorSet;
+    }
+
+    private Animator getLocationUpdateFadeInAnimator() {
+        final float shift =
+                getResources().getDisplayMetrics().widthPixels * FADE_IN_ANIM_POSITION_SHIFT;
+        final float startTx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
+
+        ValueAnimator positionAnim = new SpringAnimationBuilder(getContext())
+                .setStartValue(startTx)
+                .setEndValue(0)
+                .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+                .setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
+                .build(this, VIEW_TRANSLATE_X);
+
+        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 1f)
+                .setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
+
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(positionAnim, alphaAnim);
+        return animatorSet;
+    }
+
     /**
      * Updates the bounds with translation that may have been applied and returns the result.
      */
     public Rect getBubbleBarBounds() {
-        mBubbleBarBounds.top = getTop() + (int) getTranslationY();
+        mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize;
         mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
         return mBubbleBarBounds;
     }
@@ -230,6 +484,40 @@
         return mRelativePivotY;
     }
 
+    /** Prepares for animating a bubble while being stashed. */
+    public void prepareForAnimatingBubbleWhileStashed(String bubbleKey) {
+        mIsAnimatingNewBubble = true;
+        // we're about to animate the new bubble in. the new bubble has already been added to this
+        // view, but we're currently stashed, so before we can start the animation we need make
+        // everything else in the bubble bar invisible, except for the bubble that's being animated.
+        setBackground(null);
+        for (int i = 0; i < getChildCount(); i++) {
+            final BubbleView view = (BubbleView) getChildAt(i);
+            final String key = view.getBubble().getKey();
+            if (!bubbleKey.equals(key)) {
+                view.setVisibility(INVISIBLE);
+            }
+        }
+        setVisibility(VISIBLE);
+        setAlpha(1);
+        setTranslationY(0);
+        setScaleX(1);
+        setScaleY(1);
+    }
+
+    /** Resets the state after the bubble animation completed. */
+    public void onAnimatingBubbleCompleted() {
+        mIsAnimatingNewBubble = false;
+        // setting the background triggers relayout so no need to explicitly invalidate after the
+        // animation
+        setBackground(mBubbleBarBackground);
+        for (int i = 0; i < getChildCount(); i++) {
+            final BubbleView view = (BubbleView) getChildAt(i);
+            view.setVisibility(VISIBLE);
+            view.setAlpha(1f);
+        }
+    }
+
     // TODO: (b/280605790) animate it
     @Override
     public void addView(View child, int index, ViewGroup.LayoutParams params) {
@@ -255,6 +543,13 @@
         setLayoutParams(lp);
     }
 
+    private void updateLayoutParams() {
+        LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+        lp.height = getBubbleBarHeight();
+        lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
+        setLayoutParams(lp);
+    }
+
     /** @return the horizontal margin between the bubble bar and the edge of the screen. */
     int getHorizontalMargin() {
         LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -266,6 +561,12 @@
      * on the expanded state.
      */
     private void updateChildrenRenderNodeProperties() {
+        if (mIsAnimatingNewBubble) {
+            // don't update bubbles if a new bubble animation is playing.
+            // the bubble bar will redraw itself via onLayout after the animation.
+            return;
+        }
+
         final float widthState = (float) mWidthAnimator.getAnimatedValue();
         final float currentWidth = getWidth();
         final float expandedWidth = expandedWidth();
@@ -273,18 +574,31 @@
         int bubbleCount = getChildCount();
         final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
         final boolean animate = getVisibility() == VISIBLE;
+        final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
         for (int i = 0; i < bubbleCount; i++) {
             BubbleView bv = (BubbleView) getChildAt(i);
             bv.setTranslationY(ty);
 
             // the position of the bubble when the bar is fully expanded
-            final float expandedX = i * (mIconSize + mIconSpacing);
+            final float expandedX;
             // the position of the bubble when the bar is fully collapsed
-            final float collapsedX = i == 0 ? 0 : mIconOverlapAmount;
+            final float collapsedX;
+            if (onLeft) {
+                // If bar is on the left, bubbles are ordered right to left
+                expandedX = (bubbleCount - i - 1) * (mIconSize + mExpandedBarIconsSpacing);
+                // Shift the first bubble only if there are more bubbles in addition to overflow
+                collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0;
+            } else {
+                // Bubbles ordered left to right, don't move the first bubble
+                expandedX = i * (mIconSize + mExpandedBarIconsSpacing);
+                collapsedX = i == 0 ? 0 : mIconOverlapAmount;
+            }
 
             if (mIsBarExpanded) {
+                // If bar is on the right, account for bubble bar expanding and shifting left
+                final float expandedBarShift = onLeft ? 0 : currentWidth - expandedWidth;
                 // where the bubble will end up when the animation ends
-                final float targetX = currentWidth - expandedWidth + expandedX;
+                final float targetX = expandedX + expandedBarShift;
                 bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
                 // if we're fully expanded, set the z level to 0 or to bubble elevation if dragged
                 if (widthState == 1f) {
@@ -294,7 +608,9 @@
                 bv.setBehindStack(false, animate);
                 bv.setAlpha(1);
             } else {
-                final float targetX = currentWidth - collapsedWidth + collapsedX;
+                // If bar is on the right, account for bubble bar expanding and shifting left
+                final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth;
+                final float targetX = collapsedX + collapsedBarShift;
                 bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
                 bv.setZ((MAX_BUBBLES * mBubbleElevation) - i);
                 // If we're not the first bubble we're behind the stack
@@ -316,18 +632,22 @@
         final float expandedArrowPosition = arrowPositionForSelectedWhenExpanded();
         final float interpolatedWidth =
                 widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
-        if (mIsBarExpanded) {
-            // when the bar is expanding, the selected bubble is always the first, so the arrow
-            // always shifts with the interpolated width.
-            final float arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
-            mBubbleBarBackground.setArrowPosition(arrowPosition);
-        } else {
-            final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
-            final float arrowPosition =
-                    targetPosition + widthState * (expandedArrowPosition - targetPosition);
-            mBubbleBarBackground.setArrowPosition(arrowPosition);
-        }
+        final float arrowPosition;
 
+        float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
+        if (onLeft) {
+            arrowPosition = collapsedArrowPosition + interpolatedShift;
+        } else {
+            if (mIsBarExpanded) {
+                arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition
+                        + interpolatedShift;
+            } else {
+                final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
+                arrowPosition =
+                        targetPosition + widthState * (expandedArrowPosition - targetPosition);
+            }
+        }
+        mBubbleBarBackground.setArrowPosition(arrowPosition);
         mBubbleBarBackground.setArrowAlpha((int) (255 * widthState));
         mBubbleBarBackground.setWidth(interpolatedWidth);
     }
@@ -392,12 +712,14 @@
             Log.w(TAG, "trying to update selection arrow without a selected view!");
             return;
         }
-        final int index = indexOfChild(mSelectedBubbleView);
         // Find the center of the bubble when it's expanded, set the arrow position to it.
-        final float tx = getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
-
+        final float tx = arrowPositionForSelectedWhenExpanded();
+        final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
+        if (shouldAnimate && currentArrowPosition > expandedWidth()) {
+            Log.d(TAG, "arrow out of bounds of expanded view, skip animation");
+            shouldAnimate = false;
+        }
         if (shouldAnimate) {
-            final float currentArrowPosition = mBubbleBarBackground.getArrowPositionX();
             ValueAnimator animator = ValueAnimator.ofFloat(currentArrowPosition, tx);
             animator.setDuration(ARROW_POSITION_ANIMATION_DURATION_MS);
             animator.addUpdateListener(animation -> {
@@ -414,12 +736,28 @@
 
     private float arrowPositionForSelectedWhenExpanded() {
         final int index = indexOfChild(mSelectedBubbleView);
-        return getPaddingStart() + index * (mIconSize + mIconSpacing) + mIconSize / 2f;
+        final int bubblePosition;
+        if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+            // Bubble positions are reversed. First bubble is on the right.
+            bubblePosition = getChildCount() - index - 1;
+        } else {
+            bubblePosition = index;
+        }
+        return getPaddingStart() + bubblePosition * (mIconSize + mExpandedBarIconsSpacing)
+                + mIconSize / 2f;
     }
 
     private float arrowPositionForSelectedWhenCollapsed() {
         final int index = indexOfChild(mSelectedBubbleView);
-        return getPaddingStart() + index * (mIconOverlapAmount) + mIconSize / 2f;
+        final int bubblePosition;
+        if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
+            // Bubble positions are reversed. First bubble may be shifted, if there are more
+            // bubbles than the current bubble and overflow.
+            bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0;
+        } else {
+            bubblePosition = index;
+        }
+        return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f;
     }
 
     @Override
@@ -459,10 +797,17 @@
         return mIsBarExpanded;
     }
 
-    private float expandedWidth() {
+    /**
+     * Get width of the bubble bar as if it would be expanded.
+     *
+     * @return width of the bubble bar in its expanded state, regardless of current width
+     */
+    public float expandedWidth() {
         final int childCount = getChildCount();
         final int horizontalPadding = getPaddingStart() + getPaddingEnd();
-        return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
+        // spaces amount is less than child count by 1, or 0 if no child views
+        int spacesCount = Math.max(childCount - 1, 0);
+        return childCount * mIconSize + spacesCount * mExpandedBarIconsSpacing + horizontalPadding;
     }
 
     private float collapsedWidth() {
@@ -475,6 +820,10 @@
                 : mIconSize + horizontalPadding;
     }
 
+    private int getBubbleBarHeight() {
+        return (int) (mIconSize + mBubbleBarPadding * 2 + mPointerSize);
+    }
+
     /**
      * Returns whether the given MotionEvent, *in screen coordinates*, is within bubble bar
      * touch bounds.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 065dd58..0e62eaf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,14 +18,19 @@
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 
+import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.widget.FrameLayout;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatedFloat;
@@ -33,9 +38,11 @@
 import com.android.launcher3.taskbar.TaskbarControllers;
 import com.android.launcher3.taskbar.TaskbarInsetsController;
 import com.android.launcher3.taskbar.TaskbarStashController;
+import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.SystemUiProxy;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
 
 import java.util.List;
 import java.util.Objects;
@@ -48,11 +55,13 @@
 public class BubbleBarViewController {
 
     private static final String TAG = BubbleBarViewController.class.getSimpleName();
-
+    private static final float APP_ICON_SMALL_DP = 44f;
+    private static final float APP_ICON_MEDIUM_DP = 48f;
+    private static final float APP_ICON_LARGE_DP = 52f;
     private final SystemUiProxy mSystemUiProxy;
     private final TaskbarActivityContext mActivity;
     private final BubbleBarView mBarView;
-    private final int mIconSize;
+    private int mIconSize;
 
     // Initialized in init.
     private BubbleStashController mBubbleStashController;
@@ -78,13 +87,21 @@
     private boolean mHiddenForNoBubbles = true;
     private boolean mShouldShowEducation;
 
+    private BubbleBarViewAnimator mBubbleBarViewAnimator;
+
+    @Nullable
+    private BubbleBarBoundsChangeListener mBoundsChangeListener;
+
+    private final Rect mPreviousBubbleBarBounds = new Rect();
+
     public BubbleBarViewController(TaskbarActivityContext activity, BubbleBarView barView) {
         mActivity = activity;
         mBarView = barView;
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
         mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
         mBubbleBarAlpha.setUpdateVisibility(true);
-        mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+        mIconSize = activity.getResources().getDimensionPixelSize(
+                R.dimen.bubblebar_icon_size);
     }
 
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -94,18 +111,26 @@
         mTaskbarStashController = controllers.taskbarStashController;
         mTaskbarInsetsController = controllers.taskbarInsetsController;
 
-        mActivity.addOnDeviceProfileChangeListener(dp ->
-                mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight
-        );
-        mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight;
+        mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
+        setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
         mBubbleBarScale.updateValue(1f);
         mBubbleClickListener = v -> onBubbleClicked(v);
         mBubbleBarClickListener = v -> onBubbleBarClicked();
         mBubbleDragController.setupBubbleBarView(mBarView);
         mBarView.setOnClickListener(mBubbleBarClickListener);
-        mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
-                mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
-        );
+        mBarView.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
+                    Rect bubbleBarBounds = mBarView.getBubbleBarBounds();
+                    if (!bubbleBarBounds.equals(mPreviousBubbleBarBounds)) {
+                        mPreviousBubbleBarBounds.set(bubbleBarBounds);
+                        if (mBoundsChangeListener != null) {
+                            mBoundsChangeListener.onBoundsChanged(bubbleBarBounds);
+                        }
+                    }
+                });
+
+        mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
     }
 
     private void onBubbleClicked(View v) {
@@ -168,6 +193,20 @@
     }
 
     /**
+     * @return current {@link BubbleBarLocation}
+     */
+    public BubbleBarLocation getBubbleBarLocation() {
+        return mBarView.getBubbleBarLocation();
+    }
+
+    /**
+     * Update bar {@link BubbleBarLocation}
+     */
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
+        mBarView.setBubbleBarLocation(bubbleBarLocation, animate);
+    }
+
+    /**
      * The bounds of the bubble bar.
      */
     public Rect getBubbleBarBounds() {
@@ -212,16 +251,52 @@
         if (mHiddenForNoBubbles != hidden) {
             mHiddenForNoBubbles = hidden;
             updateVisibilityForStateChange();
+            if (hidden) {
+                mBarView.setAlpha(0);
+                mBarView.setExpanded(false);
+            }
             mActivity.bubbleBarVisibilityChanged(!hidden);
         }
     }
 
+    private void setBubbleBarIconSize(int newIconSize) {
+        if (newIconSize == mIconSize) {
+            return;
+        }
+        Resources res = mActivity.getResources();
+        DisplayMetrics dm = res.getDisplayMetrics();
+        float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_SMALL_DP, dm);
+        float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_MEDIUM_DP, dm);
+        float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                APP_ICON_LARGE_DP, dm);
+        float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
+        float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
+        mIconSize = newIconSize <= smallMediumThreshold
+                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
+                res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+        float bubbleBarPadding = newIconSize >= mediumLargeThreshold
+                ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
+                res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+
+        mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
+        mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
+                (int) bubbleBarPadding,
+                mBarView.getPaddingBottom());
+    }
+
     /** Sets a callback that updates the selected bubble after the bubble bar collapses. */
     public void setUpdateSelectedBubbleAfterCollapse(
             Consumer<String> updateSelectedBubbleAfterCollapse) {
         mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
     }
 
+    /** Returns whether the bubble bar should be hidden because of the current sysui state. */
+    boolean isHiddenForSysui() {
+        return mHiddenForSysui;
+    }
+
     /**
      * Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
      */
@@ -238,8 +313,6 @@
             mBarView.setVisibility(VISIBLE);
         } else {
             mBarView.setVisibility(INVISIBLE);
-            mBarView.setAlpha(0);
-            mBarView.setExpanded(false);
         }
     }
 
@@ -287,11 +360,22 @@
     /**
      * Adds the provided bubble to the bubble bar.
      */
-    public void addBubble(BubbleBarItem b) {
+    public void addBubble(BubbleBarItem b, boolean isExpanding, boolean suppressAnimation) {
         if (b != null) {
-            mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize));
+            mBarView.addView(b.getView(), 0,
+                    new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT));
             b.getView().setOnClickListener(mBubbleClickListener);
             mBubbleDragController.setupBubbleView(b.getView());
+
+            if (suppressAnimation) {
+                return;
+            }
+
+            boolean isInApp = mTaskbarStashController.isInApp();
+            // only animate the new bubble if we're in an app and not auto expanding
+            if (b instanceof BubbleBarBubble && isInApp && !isExpanding) {
+                mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
+            }
         } else {
             Log.w(TAG, "addBubble, bubble was null!");
         }
@@ -391,4 +475,19 @@
     public void onDismissAllBubblesWhileDragging() {
         mSystemUiProxy.removeAllBubbles();
     }
+
+    /**
+     * Set listener to be notified when bubble bar bounds have changed
+     */
+    public void setBoundsChangeListener(@Nullable BubbleBarBoundsChangeListener listener) {
+        mBoundsChangeListener = listener;
+    }
+
+    /**
+     * Listener to receive updates about bubble bar bounds changing
+     */
+    public interface BubbleBarBoundsChangeListener {
+        /** Called when bounds have changed */
+        void onBoundsChanged(Rect newBounds);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index c47427d..90f1be3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -29,6 +29,7 @@
     public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
     public final BubbleDragController bubbleDragController;
     public final BubbleDismissController bubbleDismissController;
+    public final BubbleBarPinController bubbleBarPinController;
 
     private final RunnableList mPostInitRunnables = new RunnableList();
 
@@ -43,13 +44,15 @@
             BubbleStashController bubbleStashController,
             BubbleStashedHandleViewController bubbleStashedHandleViewController,
             BubbleDragController bubbleDragController,
-            BubbleDismissController bubbleDismissController) {
+            BubbleDismissController bubbleDismissController,
+            BubbleBarPinController bubbleBarPinController) {
         this.bubbleBarController = bubbleBarController;
         this.bubbleBarViewController = bubbleBarViewController;
         this.bubbleStashController = bubbleStashController;
         this.bubbleStashedHandleViewController = bubbleStashedHandleViewController;
         this.bubbleDragController = bubbleDragController;
         this.bubbleDismissController = bubbleDismissController;
+        this.bubbleBarPinController = bubbleBarPinController;
     }
 
     /**
@@ -64,6 +67,7 @@
         bubbleStashController.init(taskbarControllers, this);
         bubbleDragController.init(/* bubbleControllers = */ this);
         bubbleDismissController.init(/* bubbleControllers = */ this);
+        bubbleBarPinController.init(this);
 
         mPostInitRunnables.executeAllAndDestroy();
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 41c3dec..a40f33c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -67,6 +67,9 @@
     @Nullable
     private BubbleDragAnimator mAnimator;
 
+    @Nullable
+    private Listener mListener;
+
     public BubbleDismissController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) {
         mActivity = activity;
         mDragLayer = dragLayer;
@@ -82,6 +85,13 @@
     }
 
     /**
+     * Set listener to be notified of dismiss events
+     */
+    public void setListener(@Nullable Listener listener) {
+        mListener = listener;
+    }
+
+    /**
      * Setup the dismiss view and magnetized object that will be attracted to magnetic target.
      * Should be called before handling events or showing/hiding dismiss view.
      *
@@ -185,22 +195,37 @@
         }
         mMagnetizedObject.setMagnetListener(new MagnetizedObject.MagnetListener() {
             @Override
-            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+            public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    @NonNull MagnetizedObject<?> draggedObject) {
                 if (mAnimator == null) return;
                 mAnimator.animateDismissCaptured();
+                if (mListener != null) {
+                    mListener.onStuckToDismissChanged(true /* stuck */);
+                }
             }
 
             @Override
             public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    @NonNull MagnetizedObject<?> draggedObject,
                     float velX, float velY, boolean wasFlungOut) {
                 if (mAnimator == null) return;
                 mAnimator.animateDismissReleased();
+                if (mListener != null) {
+                    mListener.onStuckToDismissChanged(false /* stuck */);
+                }
             }
 
             @Override
-            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+            public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target,
+                    @NonNull MagnetizedObject<?> draggedObject) {
                 dismissMagnetizedObject();
             }
         });
     }
+
+    /** Interface to receive updates about the dismiss state */
+    public interface Listener {
+        /** Called when view is stuck or unstuck from dismiss target */
+        void onStuckToDismissChanged(boolean stuck);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 24dca5e..8b811d9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -18,7 +18,6 @@
 
 import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY;
 import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW;
-import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM;
 
 import android.content.res.Resources;
 import android.graphics.PointF;
@@ -30,9 +29,9 @@
 import androidx.dynamicanimation.animation.FloatPropertyCompat;
 
 import com.android.launcher3.R;
-import com.android.wm.shell.animation.PhysicsAnimator;
 import com.android.wm.shell.common.bubbles.DismissCircleView;
 import com.android.wm.shell.common.bubbles.DismissView;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
 
 /**
  * The animator performs the bubble animations while dragging and coordinates bubble and dismiss
@@ -42,11 +41,14 @@
     private static final float SCALE_BUBBLE_FOCUSED = 1.2f;
     private static final float SCALE_BUBBLE_CAPTURED = 0.9f;
     private static final float SCALE_BUBBLE_BAR_FOCUSED = 1.1f;
+    // 400f matches to MEDIUM_LOW spring stiffness
+    private static final float TRANSLATION_SPRING_STIFFNESS = 400f;
 
     private final PhysicsAnimator.SpringConfig mDefaultConfig =
             new PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_LOW_BOUNCY);
     private final PhysicsAnimator.SpringConfig mTranslationConfig =
-            new PhysicsAnimator.SpringConfig(STIFFNESS_MEDIUM, DAMPING_RATIO_LOW_BOUNCY);
+            new PhysicsAnimator.SpringConfig(TRANSLATION_SPRING_STIFFNESS,
+                    DAMPING_RATIO_LOW_BOUNCY);
     @NonNull
     private final View mView;
     @NonNull
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 08fd681..5ffc6d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -28,7 +28,7 @@
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 
 /**
- * Controls bubble bar drag to dismiss interaction.
+ * Controls bubble bar drag interactions.
  * Interacts with {@link BubbleDismissController}, used by {@link BubbleBarViewController}.
  * Supported interactions:
  * - Drag a single bubble view into dismiss target to remove it.
@@ -39,6 +39,7 @@
     private final TaskbarActivityContext mActivity;
     private BubbleBarViewController mBubbleBarViewController;
     private BubbleDismissController mBubbleDismissController;
+    private BubbleBarPinController mBubbleBarPinController;
 
     public BubbleDragController(TaskbarActivityContext activity) {
         mActivity = activity;
@@ -52,6 +53,11 @@
     public void init(@NonNull BubbleControllers bubbleControllers) {
         mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
         mBubbleDismissController = bubbleControllers.bubbleDismissController;
+        mBubbleBarPinController = bubbleControllers.bubbleBarPinController;
+        mBubbleBarPinController.setListener(
+                bubbleControllers.bubbleBarController::updateBubbleBarLocation);
+        mBubbleDismissController.setListener(
+                stuck -> mBubbleBarPinController.setDropTargetHidden(stuck));
     }
 
     /**
@@ -89,6 +95,7 @@
     public void setupBubbleBarView(@NonNull BubbleBarView bubbleBarView) {
         PointF initialRelativePivot = new PointF();
         bubbleBarView.setOnTouchListener(new BubbleTouchListener() {
+
             @Override
             protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) {
                 if (bubbleBarView.isExpanded()) return false;
@@ -102,12 +109,38 @@
                 // By default the bubble bar view pivot is in bottom right corner, while dragging
                 // it should be centered in order to align it with the dismiss target view
                 bubbleBarView.setRelativePivot(/* x = */ 0.5f, /* y = */ 0.5f);
+                bubbleBarView.setIsDragging(true);
+                mBubbleBarPinController.onDragStart(
+                        bubbleBarView.getBubbleBarLocation().isOnLeft(bubbleBarView.isLayoutRtl()));
+            }
+
+            @Override
+            protected void onDragUpdate(float x, float y) {
+                mBubbleBarPinController.onDragUpdate(x, y);
+            }
+
+            @Override
+            protected void onDragRelease() {
+                mBubbleBarPinController.onDragEnd();
+            }
+
+            @Override
+            protected void onDragDismiss() {
+                mBubbleBarPinController.onDragEnd();
             }
 
             @Override
             void onDragEnd() {
                 // Restoring the initial pivot for the bubble bar view
                 bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
+                bubbleBarView.setIsDragging(false);
+            }
+
+            @Override
+            protected PointF getRestingPosition() {
+                PointF restingPosition = super.getRestingPosition();
+                bubbleBarView.adjustRelativeRestingPosition(restingPosition);
+                return restingPosition;
             }
         });
     }
@@ -170,6 +203,13 @@
         abstract void onDragStart();
 
         /**
+         * Called when bubble is dragged to new coordinates.
+         * Not called while bubble is stuck to the dismiss target.
+         */
+        protected void onDragUpdate(float x, float y) {
+        }
+
+        /**
          * Called when the dragging interaction has ended and all the animations have completed
          */
         abstract void onDragEnd();
@@ -188,6 +228,13 @@
         protected void onDragDismiss() {
         }
 
+        /**
+         * Get the resting position of the view when drag is released
+         */
+        protected PointF getRestingPosition() {
+            return mViewInitialPosition;
+        }
+
         @Override
         @SuppressLint("ClickableViewAccessibility")
         public boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {
@@ -232,8 +279,10 @@
          * @param event the motion event
          */
         protected void onTouchMove(@NonNull View view, @NonNull MotionEvent event) {
-            final float dx = event.getRawX() - mTouchDownLocation.x;
-            final float dy = event.getRawY() - mTouchDownLocation.y;
+            float rawX = event.getRawX();
+            float rawY = event.getRawY();
+            final float dx = rawX - mTouchDownLocation.x;
+            final float dy = rawY - mTouchDownLocation.y;
             switch (mState) {
                 case TOUCHED:
                     final boolean movedOut = Math.hypot(dx, dy) > mTouchSlop;
@@ -244,7 +293,7 @@
                     }
                     break;
                 case DRAGGING:
-                    drag(view, event, dx, dy);
+                    drag(view, event, dx, dy, rawX, rawY);
                     break;
             }
         }
@@ -293,10 +342,12 @@
             mBubbleDismissController.showDismissView();
         }
 
-        private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy) {
+        private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy,
+                float x, float y) {
             if (mBubbleDismissController.handleTouchEvent(event)) return;
             view.setTranslationX(mViewInitialPosition.x + dx);
             view.setTranslationY(mViewInitialPosition.y + dy);
+            onDragUpdate(x, y);
         }
 
         private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
@@ -311,7 +362,7 @@
                 mAnimator.animateDismiss(mViewInitialPosition, onComplete);
             } else {
                 onDragRelease();
-                mAnimator.animateToInitialState(mViewInitialPosition, getCurrentVelocity(),
+                mAnimator.animateToInitialState(getRestingPosition(), getCurrentVelocity(),
                         onComplete);
             }
             mBubbleDismissController.hideDismissView();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 09021ed..76d86de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.view.InsetsController;
 import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.StashedHandleViewController;
@@ -31,6 +32,8 @@
 import com.android.launcher3.taskbar.TaskbarInsetsController;
 import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.util.MultiPropertyFactory;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
 
 /**
  * Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
@@ -356,4 +359,19 @@
     public boolean isEventOverStashHandle(MotionEvent ev) {
         return mHandleViewController.isEventOverHandle(ev);
     }
+
+    /** Set a bubble bar location */
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
+    }
+
+    /** Returns the x position of the center of the stashed handle. */
+    public float getStashedHandleCenterX() {
+        return mHandleViewController.getStashedHandleCenterX();
+    }
+
+    /** Returns the [PhysicsAnimator] for the stashed handle view. */
+    public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
+        return mHandleViewController.getPhysicsAnimator();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index c998d97..6f1a093 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -38,6 +38,8 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
 
 /**
  * Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -46,7 +48,7 @@
 
     private final TaskbarActivityContext mActivity;
     private final StashedHandleView mStashedHandleView;
-    private final MultiValueAlpha mTaskbarStashedHandleAlpha;
+    private final MultiValueAlpha mStashedHandleAlpha;
 
     // Initialized in init.
     private BubbleBarViewController mBarViewController;
@@ -74,7 +76,7 @@
             StashedHandleView stashedHandleView) {
         mActivity = activity;
         mStashedHandleView = stashedHandleView;
-        mTaskbarStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
+        mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
     }
 
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -92,7 +94,7 @@
                 R.dimen.transient_taskbar_bottom_margin);
         mStashedHandleView.getLayoutParams().height = mBarSize + bottomMargin;
 
-        mTaskbarStashedHandleAlpha.get(0).setValue(0);
+        mStashedHandleAlpha.get(0).setValue(0);
 
         mStashedTaskbarHeight = resources.getDimensionPixelSize(
                 R.dimen.bubblebar_stashed_size);
@@ -118,25 +120,38 @@
                 }, Executors.UI_HELPER_EXECUTOR);
 
         mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
-                updateBounds());
+                updateBounds(mBarViewController.getBubbleBarLocation()));
     }
 
-    private void updateBounds() {
+    /** Returns the [PhysicsAnimator] for the stashed handle view. */
+    public PhysicsAnimator<View> getPhysicsAnimator() {
+        return PhysicsAnimator.getInstance(mStashedHandleView);
+    }
+
+    private void updateBounds(BubbleBarLocation bubbleBarLocation) {
         // As more bubbles get added, the icon bounds become larger. To ensure a consistent
         // handle bar position, we pin it to the edge of the screen.
-        final int right =
-                mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
-
         final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
+        if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
+            final int left = mBarViewController.getHorizontalMargin();
+            mStashedHandleBounds.set(
+                    left,
+                    stashedCenterY - mStashedHandleHeight / 2,
+                    left + mStashedHandleWidth,
+                    stashedCenterY + mStashedHandleHeight / 2);
+            mStashedHandleView.setPivotX(0);
+        } else {
+            final int right =
+                    mActivity.getDeviceProfile().widthPx - mBarViewController.getHorizontalMargin();
+            mStashedHandleBounds.set(
+                    right - mStashedHandleWidth,
+                    stashedCenterY - mStashedHandleHeight / 2,
+                    right,
+                    stashedCenterY + mStashedHandleHeight / 2);
+            mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
+        }
 
-        mStashedHandleBounds.set(
-                right - mStashedHandleWidth,
-                stashedCenterY - mStashedHandleHeight / 2,
-                right,
-                stashedCenterY + mStashedHandleHeight / 2);
         mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
-
-        mStashedHandleView.setPivotX(mStashedHandleView.getWidth());
         mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
     }
 
@@ -233,7 +248,12 @@
      * Used by {@link BubbleStashController} to animate the handle when stashing or un stashing.
      */
     public MultiPropertyFactory<View> getStashedHandleAlpha() {
-        return mTaskbarStashedHandleAlpha;
+        return mStashedHandleAlpha;
+    }
+
+    /** Returns the x position of the center of the stashed handle. */
+    public float getStashedHandleCenterX() {
+        return mStashedHandleBounds.exactCenterX();
     }
 
     /**
@@ -287,4 +307,9 @@
     public boolean containsX(int x) {
         return x >= mStashedHandleBounds.left && x <= mStashedHandleBounds.right;
     }
+
+    /** Set a bubble bar location */
+    public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
+        updateBounds(bubbleBarLocation);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 6549ad6..bcdc718 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -145,7 +145,7 @@
     }
 
     /** Sets the bubble being rendered in this view. */
-    void setBubble(BubbleBarBubble bubble) {
+    public void setBubble(BubbleBarBubble bubble) {
         mBubble = bubble;
         mBubbleIcon.setImageBitmap(bubble.getIcon());
         mAppIcon.setImageBitmap(bubble.getBadge());
@@ -159,7 +159,7 @@
      * the list of bubbles. It doesn't show an app icon because it is part of system UI / doesn't
      * come from an app.
      */
-    void setOverflow(BubbleBarOverflow overflow, Bitmap bitmap) {
+    public void setOverflow(BubbleBarOverflow overflow, Bitmap bitmap) {
         mBubble = overflow;
         mBubbleIcon.setImageBitmap(bitmap);
         mAppIcon.setVisibility(GONE); // Overflow doesn't show the app badge
@@ -168,7 +168,7 @@
 
     /** Returns the bubble being rendered in this view. */
     @Nullable
-    BubbleBarItem getBubble() {
+    public BubbleBarItem getBubble() {
         return mBubble;
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
index 7af0389..3f947a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -1 +1,5 @@
+atsjenk@google.com
+liranb@google.com
 madym@google.com
+mpodolian@google.com
+
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
new file mode 100644
index 0000000..2d8983f
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.animation
+
+import android.view.View
+import android.view.View.VISIBLE
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
+import com.android.launcher3.taskbar.bubbles.BubbleBarView
+import com.android.launcher3.taskbar.bubbles.BubbleStashController
+import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.wm.shell.shared.animation.PhysicsAnimator
+
+/** Handles animations for bubble bar bubbles. */
+class BubbleBarViewAnimator
+@JvmOverloads
+constructor(
+    private val bubbleBarView: BubbleBarView,
+    private val bubbleStashController: BubbleStashController,
+    private val scheduler: Scheduler = HandlerScheduler(bubbleBarView)
+) {
+
+    private companion object {
+        /** The time to show the flyout. */
+        const val FLYOUT_DELAY_MS: Long = 2500
+        /** The translation Y the new bubble will animate to. */
+        const val BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y = -50f
+        /** The initial translation Y value the new bubble is set to before the animation starts. */
+        // TODO(liranb): get rid of this and calculate this based on the y-distance between the
+        // bubble and the stash handle.
+        const val BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET = 50f
+        /** The initial scale Y value that the new bubble is set to before the animation starts. */
+        const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
+        /**
+         * The distance the stashed handle will travel as it gets hidden as part of the new bubble
+         * animation.
+         */
+        // TODO(liranb): calculate this based on the position of the views
+        const val BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y = -20f
+    }
+
+    /** An interface for scheduling jobs. */
+    interface Scheduler {
+
+        /** Schedule the given [block] to run. */
+        fun post(block: () -> Unit)
+
+        /** Schedule the given [block] to start with a delay of [delayMillis]. */
+        fun postDelayed(delayMillis: Long, block: () -> Unit)
+    }
+
+    /** A [Scheduler] that uses a Handler to run jobs. */
+    private class HandlerScheduler(private val view: View) : Scheduler {
+
+        override fun post(block: () -> Unit) {
+            view.post(block)
+        }
+
+        override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+            view.postDelayed(block, delayMillis)
+        }
+    }
+
+    private val springConfig =
+        PhysicsAnimator.SpringConfig(
+            stiffness = SpringForce.STIFFNESS_LOW,
+            dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
+        )
+
+    /** Animates a bubble for the state where the bubble bar is stashed. */
+    fun animateBubbleInForStashed(b: BubbleBarBubble) {
+        val bubbleView = b.view
+        val animator = PhysicsAnimator.getInstance(bubbleView)
+        if (animator.isRunning()) animator.cancel()
+        // the animation of a new bubble is divided into 2 parts. The first part shows the bubble
+        // and the second part hides it after a delay.
+        val showAnimation = buildShowAnimation(bubbleView, b.key)
+        val hideAnimation = buildHideAnimation(bubbleView)
+        scheduler.post(showAnimation)
+        scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
+    }
+
+    /**
+     * Returns a lambda that starts the animation that shows the new bubble.
+     *
+     * Visually, the animation is divided into 2 parts. The stash handle starts animating up and
+     * fading out and then the bubble starts animating up and fading in.
+     *
+     * To make the transition from the handle to the bubble smooth, the positions and movement of
+     * the 2 views must be synchronized. To do that we use a single spring path along the Y axis,
+     * starting from the handle's position to the eventual bubble's position. The path is split into
+     * 3 parts.
+     * 1. In the first part, we only animate the handle.
+     * 1. In the second part the handle is fully hidden, and the bubble is animating in.
+     * 1. The third part is the overshoot of the spring animation, where we make the bubble fully
+     *    visible which helps avoiding further updates when we re-enter the second part.
+     */
+    private fun buildShowAnimation(
+        bubbleView: BubbleView,
+        key: String,
+    ): () -> Unit = {
+        bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
+        // calculate the initial translation x the bubble should have in order to align it with the
+        // stash handle.
+        val initialTranslationX =
+            bubbleStashController.stashedHandleCenterX - bubbleView.centerXOnScreen
+        // prepare the bubble for the animation
+        bubbleView.alpha = 0f
+        bubbleView.translationX = initialTranslationX
+        bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
+        bubbleView.visibility = VISIBLE
+
+        // this is the total distance that both the stashed handle and the bubble will be traveling
+        val totalTranslationY =
+            BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+        val animator = bubbleStashController.stashedHandlePhysicsAnimator
+        animator.setDefaultSpringConfig(springConfig)
+        animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
+        animator.addUpdateListener { target, values ->
+            val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+            when {
+                ty >= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+                    // we're in the first leg of the animation. only animate the handle. the bubble
+                    // remains hidden during this part of the animation
+
+                    // map the path [0, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y] to [0,1]
+                    val fraction = ty / BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+                    target.alpha = 1 - fraction / 2
+                }
+                ty >= totalTranslationY -> {
+                    // this is the second leg of the animation. the handle should be completely
+                    // hidden and the bubble should start animating in.
+                    // it's possible that we're re-entering this leg because this is a spring
+                    // animation, so only set the alpha and scale for the bubble if we didn't
+                    // already fully animate in.
+                    target.alpha = 0f
+                    bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+                    if (bubbleView.alpha != 1f) {
+                        // map the path
+                        // [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, totalTranslationY]
+                        // to [0, 1]
+                        val fraction =
+                            (ty - BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y) /
+                                BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
+                        bubbleView.alpha = fraction
+                        bubbleView.scaleY =
+                            BUBBLE_ANIMATION_INITIAL_SCALE_Y +
+                                (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+                    }
+                }
+                else -> {
+                    // we're past the target animated value, set the alpha and scale for the bubble
+                    // so that it's fully visible and no longer changing, but keep moving it along
+                    // the animation path
+                    bubbleView.alpha = 1f
+                    bubbleView.scaleY = 1f
+                    bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+                }
+            }
+        }
+        animator.start()
+    }
+
+    /**
+     * Returns a lambda that starts the animation that hides the new bubble.
+     *
+     * Similarly to the show animation, this is visually divided into 2 parts. We first animate the
+     * bubble out, and then animate the stash handle in. At the end of the animation we reset the
+     * values of the bubble.
+     *
+     * This is a spring animation that goes along the same path of the show animation in the
+     * opposite order, and is split into 3 parts:
+     * 1. In the first part the bubble animates out.
+     * 1. In the second part the bubble is fully hidden and the handle animates in.
+     * 1. The third part is the overshoot. The handle is made fully visible.
+     */
+    private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
+        // this is the total distance that both the stashed handle and the bubble will be traveling
+        val totalTranslationY =
+            BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+        val animator = bubbleStashController.stashedHandlePhysicsAnimator
+        animator.setDefaultSpringConfig(springConfig)
+        animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
+        animator.addUpdateListener { target, values ->
+            val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+            when {
+                ty <= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+                    // this is the first leg of the animation. only animate the bubble. the handle
+                    // is hidden during this part
+                    bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+                    // map the path
+                    // [totalTranslationY, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y]
+                    // to [0, 1]
+                    val fraction = (totalTranslationY - ty) / BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
+                    bubbleView.alpha = 1 - fraction / 2
+                    bubbleView.scaleY = 1 - (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+                }
+                ty <= 0 -> {
+                    // this is the second part of the animation. make the bubble invisible and
+                    // start fading in the handle, but don't update the alpha if it's already fully
+                    // visible
+                    bubbleView.alpha = 0f
+                    if (target.alpha != 1f) {
+                        // map the path [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, 0] to [0, 1]
+                        val fraction =
+                            (BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y - ty) /
+                                BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+                        target.alpha = fraction
+                    }
+                }
+                else -> {
+                    // we reached the target value. set the alpha of the handle to 1
+                    target.alpha = 1f
+                }
+            }
+        }
+        animator.addEndListener { _, _, _, _, _, _, _ ->
+            bubbleView.alpha = 0f
+            bubbleView.translationY = 0f
+            bubbleView.scaleY = 1f
+            if (bubbleStashController.isStashed) {
+                bubbleBarView.alpha = 0f
+            }
+            bubbleBarView.onAnimatingBubbleCompleted()
+        }
+        animator.start()
+    }
+}
+
+/** The X position in screen coordinates of the center of the bubble. */
+private val BubbleView.centerXOnScreen: Float
+    get() {
+        val screenCoordinates = IntArray(2)
+        getLocationOnScreen(screenCoordinates)
+        return screenCoordinates[0] + width / 2f
+    }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index b516d6f..fe91362 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -23,6 +23,7 @@
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.Space
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
@@ -46,7 +47,8 @@
         protected val startContextualContainer: ViewGroup,
         protected val imeSwitcher: ImageView?,
         protected val rotationButton: RotationButton?,
-        protected val a11yButton: ImageView?
+        protected val a11yButton: ImageView?,
+        protected val space: Space?
 ) : NavButtonLayoutter {
     protected val homeButton: ImageView? = navButtonContainer.findViewById(R.id.home)
     protected val recentsButton: ImageView? = navButtonContainer.findViewById(R.id.recent_apps)
@@ -65,18 +67,19 @@
 
     fun getParamsToCenterView(): FrameLayout.LayoutParams {
         val params = FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
         params.gravity = Gravity.CENTER
         return params;
     }
 
-    open fun repositionContextualContainer(contextualContainer: ViewGroup, barAxisMargin: Int,
+    open fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
+                                           barAxisMarginStart: Int, barAxisMarginEnd: Int,
                                            gravity: Int) {
         val contextualContainerParams = FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+                buttonSize, ViewGroup.LayoutParams.MATCH_PARENT)
         contextualContainerParams.apply {
-            marginStart = barAxisMargin
-            marginEnd = barAxisMargin
+            marginStart = barAxisMarginStart
+            marginEnd = barAxisMarginEnd
             topMargin = 0
             bottomMargin = 0
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index 3f51958..4368b95 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -21,11 +21,13 @@
 import android.graphics.drawable.PaintDrawable
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
-import com.android.launcher3.DeviceProfile
+import android.widget.Space
 import com.android.launcher3.R
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
 import com.android.systemui.shared.rotation.RotationButton
 
@@ -36,7 +38,8 @@
         startContextualContainer: ViewGroup,
         imeSwitcher: ImageView?,
         rotationButton: RotationButton?,
-        a11yButton: ImageView?
+        a11yButton: ImageView?,
+        space: Space?
 ) :
     AbstractNavButtonLayoutter(
             resources,
@@ -45,10 +48,11 @@
             startContextualContainer,
             imeSwitcher,
             rotationButton,
-            a11yButton
+            a11yButton,
+            space
     ) {
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         val iconSize: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_ICON_SIZE_KIDS)
         val buttonWidth: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
         val buttonHeight: Int =
@@ -103,8 +107,9 @@
 
         val contextualMargin = resources.getDimensionPixelSize(
                 R.dimen.taskbar_contextual_button_padding)
-        repositionContextualContainer(endContextualContainer, 0, Gravity.END)
-        repositionContextualContainer(startContextualContainer, contextualMargin, Gravity.START)
+        repositionContextualContainer(endContextualContainer, WRAP_CONTENT, 0, 0, Gravity.END)
+        repositionContextualContainer(startContextualContainer, WRAP_CONTENT, contextualMargin,
+                contextualMargin, Gravity.START)
 
         if (imeSwitcher != null) {
             startContextualContainer.addView(imeSwitcher)
@@ -112,6 +117,7 @@
         }
         if (a11yButton != null) {
             endContextualContainer.addView(a11yButton)
+            a11yButton.layoutParams = getParamsToCenterView()
         }
         if (rotationButton != null) {
             endContextualContainer.addView(rotationButton.currentView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index 6b05e9a..5bfdce9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -20,10 +20,11 @@
 import android.view.Surface.ROTATION_90
 import android.view.Surface.Rotation
 import android.view.ViewGroup
-import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.Space
 import com.android.launcher3.DeviceProfile
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.*
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.Companion
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
@@ -54,17 +55,18 @@
          * @param isThreeButtonNav are no-ops when taskbar is present/showing
          */
         fun getUiLayoutter(
-                deviceProfile: DeviceProfile,
-                navButtonsView: FrameLayout,
-                imeSwitcher: ImageView?,
-                rotationButton: RotationButton?,
-                a11yButton: ImageView?,
-                resources: Resources,
-                isKidsMode: Boolean,
-                isInSetup: Boolean,
-                isThreeButtonNav: Boolean,
-                phoneMode: Boolean,
-                @Rotation surfaceRotation: Int
+            deviceProfile: DeviceProfile,
+            navButtonsView: NearestTouchFrame,
+            imeSwitcher: ImageView?,
+            rotationButton: RotationButton?,
+            a11yButton: ImageView?,
+            space: Space?,
+            resources: Resources,
+            isKidsMode: Boolean,
+            isInSetup: Boolean,
+            isThreeButtonNav: Boolean,
+            phoneMode: Boolean,
+            @Rotation surfaceRotation: Int
         ): NavButtonLayoutter {
             val navButtonContainer =
                 navButtonsView.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS)
@@ -77,81 +79,92 @@
             return when {
                 isPhoneNavMode -> {
                     if (!deviceProfile.isLandscape) {
+                        navButtonsView.setIsVertical(false)
                         PhonePortraitNavLayoutter(
-                                resources,
-                                navButtonContainer,
-                                endContextualContainer,
-                                startContextualContainer,
-                                imeSwitcher,
-                                rotationButton,
-                                a11yButton
-                        )
-                    } else if (surfaceRotation == ROTATION_90) {
-                        PhoneLandscapeNavLayoutter(
-                                resources,
-                                navButtonContainer,
-                                endContextualContainer,
-                                startContextualContainer,
-                                imeSwitcher,
-                                rotationButton,
-                                a11yButton
-                        )
-                    } else {
-                        PhoneSeascapeNavLayoutter(
-                                resources,
-                                navButtonContainer,
-                                endContextualContainer,
-                                startContextualContainer,
-                                imeSwitcher,
-                                rotationButton,
-                                a11yButton
-                        )
-                    }
-                }
-                isPhoneGestureMode ->{
-                    PhoneGestureLayoutter(
                             resources,
                             navButtonContainer,
                             endContextualContainer,
                             startContextualContainer,
                             imeSwitcher,
                             rotationButton,
-                            a11yButton
+                            a11yButton,
+                            space
+                        )
+                    } else if (surfaceRotation == ROTATION_90) {
+                        navButtonsView.setIsVertical(true)
+                        PhoneLandscapeNavLayoutter(
+                            resources,
+                            navButtonContainer,
+                            endContextualContainer,
+                            startContextualContainer,
+                            imeSwitcher,
+                            rotationButton,
+                            a11yButton,
+                            space
+                        )
+                    } else {
+                        navButtonsView.setIsVertical(true)
+                        PhoneSeascapeNavLayoutter(
+                            resources,
+                            navButtonContainer,
+                            endContextualContainer,
+                            startContextualContainer,
+                            imeSwitcher,
+                            rotationButton,
+                            a11yButton,
+                            space
+                        )
+                    }
+                }
+                isPhoneGestureMode -> {
+                    PhoneGestureLayoutter(
+                        resources,
+                        navButtonContainer,
+                        endContextualContainer,
+                        startContextualContainer,
+                        imeSwitcher,
+                        rotationButton,
+                        a11yButton,
+                        space
                     )
                 }
                 deviceProfile.isTaskbarPresent -> {
                     return when {
                         isInSetup -> {
                             SetupNavLayoutter(
-                                    resources,
-                                    navButtonContainer,
-                                    endContextualContainer,
-                                    startContextualContainer,
-                                    imeSwitcher,
-                                    rotationButton,
-                                    a11yButton
+                                resources,
+                                navButtonsView,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer,
+                                imeSwitcher,
+                                rotationButton,
+                                a11yButton,
+                                space
                             )
                         }
                         isKidsMode -> {
                             KidsNavLayoutter(
-                                    resources,
-                                    navButtonContainer,
-                                    endContextualContainer,
-                                    startContextualContainer,
-                                    imeSwitcher,
-                                    rotationButton,
-                                    a11yButton
+                                resources,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer,
+                                imeSwitcher,
+                                rotationButton,
+                                a11yButton,
+                                space
                             )
                         }
                         else ->
                             TaskbarNavLayoutter(
-                                    resources,
-                                    navButtonContainer,
-                                    endContextualContainer,
-                                    startContextualContainer,
-                                    imeSwitcher,
-                                    rotationButton,
-                                    a11yButton
+                                resources,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer,
+                                imeSwitcher,
+                                rotationButton,
+                                a11yButton,
+                                space
                             )
                     }
                 }
@@ -162,6 +175,6 @@
 
     /** Lays out and provides access to the home, recents, and back buttons for various mischief */
     interface NavButtonLayoutter {
-        fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean)
+        fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean)
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
new file mode 100644
index 0000000..bbf08bf
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NearestTouchFrame.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.navbutton;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Redirects touches that aren't handled by any child view to the nearest
+ * clickable child. Only takes effect on <sw600dp.
+ */
+public class NearestTouchFrame extends FrameLayout {
+
+    private final List<View> mClickableChildren = new ArrayList<>();
+    private final List<View> mAttachedChildren = new ArrayList<>();
+    private final boolean mIsActive;
+    private final int[] mTmpInt = new int[2];
+
+    // Offset (as the base) to translate window cords to view cords.
+    private final int[] mWindowOffset = new int[2];
+    private boolean mIsVertical;
+    private View mTouchingChild;
+    private final Map<View, Rect> mTouchableRegions = new HashMap<>();
+    /**
+     * Used to sort all child views either by their left position or their top position,
+     * depending on if this layout is used horizontally or vertically, respectively
+     */
+    private final Comparator<View> mChildRegionComparator =
+            (view1, view2) -> {
+                int leftTopIndex = mIsVertical ? 1 : 0;
+                view1.getLocationInWindow(mTmpInt);
+                int startingCoordView1 = mTmpInt[leftTopIndex] - mWindowOffset[leftTopIndex];
+                view2.getLocationInWindow(mTmpInt);
+                int startingCoordView2 = mTmpInt[leftTopIndex] - mWindowOffset[leftTopIndex];
+
+                return startingCoordView1 - startingCoordView2;
+            };
+
+    public NearestTouchFrame(Context context, AttributeSet attrs) {
+        this(context, attrs, context.getResources().getConfiguration());
+    }
+
+    public NearestTouchFrame(Context context, AttributeSet attrs, Configuration c) {
+        super(context, attrs);
+        mIsActive = c.smallestScreenWidthDp < 600;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        mClickableChildren.clear();
+        mAttachedChildren.clear();
+        mTouchableRegions.clear();
+        addClickableChildren(this);
+        getLocationInWindow(mWindowOffset);
+        cacheClosestChildLocations();
+    }
+
+    /**
+     * Populates {@link #mTouchableRegions} with the regions where each clickable child is the
+     * closest for a given point on this layout.
+     */
+    private void cacheClosestChildLocations() {
+        if (getWidth() == 0 || getHeight() == 0) {
+            return;
+        }
+
+        // Sort by either top or left depending on mIsVertical, then take out all children
+        // that are not attached to window
+        mClickableChildren.sort(mChildRegionComparator);
+        mClickableChildren.stream()
+                .filter(View::isAttachedToWindow)
+                .forEachOrdered(mAttachedChildren::add);
+
+        // Cache bounds of children
+        // Mark coordinates where the actual child layout resides in this frame's window
+        for (int i = 0; i < mAttachedChildren.size(); i++) {
+            View child = mAttachedChildren.get(i);
+            if (!child.isAttachedToWindow()) {
+                continue;
+            }
+            Rect childRegion = getChildsBounds(child);
+
+            // We compute closest child from this child to the previous one
+            if (i == 0) {
+                // First child, nothing to the left/top of it
+                if (mIsVertical) {
+                    childRegion.top = 0;
+                } else {
+                    childRegion.left = 0;
+                }
+                mTouchableRegions.put(child, childRegion);
+                continue;
+            }
+
+            View previousChild = mAttachedChildren.get(i - 1);
+            Rect previousChildBounds = mTouchableRegions.get(previousChild);
+            int midPoint;
+            if (mIsVertical) {
+                int distance = childRegion.top - previousChildBounds.bottom;
+                midPoint = distance / 2;
+                childRegion.top -= midPoint;
+                previousChildBounds.bottom += midPoint - ((distance % 2) == 0 ? 1 : 0);
+            } else {
+                int distance = childRegion.left - previousChildBounds.right;
+                midPoint = distance / 2;
+                childRegion.left -= midPoint;
+                previousChildBounds.right += midPoint - ((distance % 2) == 0 ? 1 : 0);
+            }
+
+            if (i == mClickableChildren.size() - 1) {
+                // Last child, nothing to right/bottom of it
+                if (mIsVertical) {
+                    childRegion.bottom = getHeight();
+                } else {
+                    childRegion.right = getWidth();
+                }
+            }
+
+            mTouchableRegions.put(child, childRegion);
+        }
+    }
+
+    void setIsVertical(boolean isVertical) {
+        mIsVertical = isVertical;
+    }
+
+    private Rect getChildsBounds(View child) {
+        child.getLocationInWindow(mTmpInt);
+        int left = mTmpInt[0] - mWindowOffset[0];
+        int top = mTmpInt[1] - mWindowOffset[1];
+        int right = left + child.getWidth();
+        int bottom = top + child.getHeight();
+        return new Rect(left, top, right, bottom);
+    }
+
+    private void addClickableChildren(ViewGroup group) {
+        final int N = group.getChildCount();
+        for (int i = 0; i < N; i++) {
+            View child = group.getChildAt(i);
+            if (child.isClickable()) {
+                mClickableChildren.add(child);
+            } else if (child instanceof ViewGroup) {
+                addClickableChildren((ViewGroup) child);
+            }
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mIsActive) {
+            int x = (int) event.getX();
+            int y = (int) event.getY();
+            if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                mTouchingChild = mClickableChildren
+                        .stream()
+                        .filter(View::isAttachedToWindow)
+                        .filter(view -> mTouchableRegions.get(view).contains(x, y))
+                        .findFirst()
+                        .orElse(null);
+
+            }
+            if (mTouchingChild != null) {
+                // Translate the touch event to the view center of the touching child.
+                event.offsetLocation(mTouchingChild.getWidth() / 2 - x,
+                        mTouchingChild.getHeight() / 2 - y);
+                return mTouchingChild.getVisibility() == VISIBLE
+                        && mTouchingChild.dispatchTouchEvent(event);
+            }
+        }
+        return super.onTouchEvent(event);
+    }
+
+    public void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(prefix + "NearestTouchFrame:");
+
+        pw.println(String.format("%s\tmWindowOffset=%s", prefix, Arrays.toString(mWindowOffset)));
+        pw.println(String.format("%s\tmIsVertical=%s", prefix, mIsVertical));
+        pw.println(String.format("%s\tmTouchingChild=%s", prefix, mTouchingChild));
+        pw.println(String.format("%s\tmTouchableRegions=%s", prefix,
+                mTouchableRegions.keySet().stream()
+                        .map(key -> key + "=" + mTouchableRegions.get(key))
+                        .collect(Collectors.joining(", ", "{", "}"))));
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
index 5a7bc49..bf820c0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneGestureLayoutter.kt
@@ -20,7 +20,8 @@
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
-import com.android.launcher3.DeviceProfile
+import android.widget.Space
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.systemui.shared.rotation.RotationButton
 
 /** Layoutter for showing gesture navigation on phone screen. No buttons here, no-op container */
@@ -31,7 +32,8 @@
         startContextualContainer: ViewGroup,
         imeSwitcher: ImageView?,
         rotationButton: RotationButton?,
-        a11yButton: ImageView?
+        a11yButton: ImageView?,
+        space: Space?
 ) :
         AbstractNavButtonLayoutter(
                 resources,
@@ -40,10 +42,11 @@
                 startContextualContainer,
                 imeSwitcher,
                 rotationButton,
-                a11yButton
+                a11yButton,
+                space
         ) {
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index 382e298..6a935f1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -19,14 +19,13 @@
 import android.content.res.Resources
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
-import androidx.core.view.children
-import com.android.launcher3.DeviceProfile
+import android.widget.Space
 import com.android.launcher3.R
-import com.android.launcher3.taskbar.TaskbarManager
-import com.android.launcher3.util.DimensionUtils
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.systemui.shared.rotation.RotationButton
 
 open class PhoneLandscapeNavLayoutter(
@@ -37,6 +36,7 @@
         imeSwitcher: ImageView?,
         rotationButton: RotationButton?,
         a11yButton: ImageView?,
+        space: Space?
 ) :
     AbstractNavButtonLayoutter(
             resources,
@@ -45,52 +45,72 @@
             startContextualContainer,
             imeSwitcher,
             rotationButton,
-            a11yButton
+            a11yButton,
+            space
     ) {
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
-        // TODO(b/230395757): Polish pending, this is just to make it usable
-        val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
-        val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
-                TaskbarManager.isPhoneMode(dp))
-        navButtonContainer.removeAllViews()
-        navButtonContainer.orientation = LinearLayout.VERTICAL
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
+        val totalHeight = context.deviceProfile.heightPx
+        val homeButtonHeight = resources.getDimensionPixelSize(
+                R.dimen.taskbar_phone_home_button_size)
+        val roundedCornerContentMargin = resources.getDimensionPixelSize(
+                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
+        val contentWidth = totalHeight - roundedCornerContentMargin * 2 - contentPadding * 2
+
+        // left:back:space(reserved for home):overview:right = 0.25:0.5:1:0.5:0.25
+        val contextualButtonHeight = contentWidth / (0.25f + 0.5f + 1f + 0.5f + 0.25f) * 0.25f
+        val sideButtonHeight = contextualButtonHeight * 2
+        val navButtonContainerHeight = contentWidth - contextualButtonHeight * 2
 
         val navContainerParams = FrameLayout.LayoutParams(
-                taskbarDimensions.x, ViewGroup.LayoutParams.MATCH_PARENT)
+                MATCH_PARENT, navButtonContainerHeight.toInt())
         navContainerParams.apply {
-            topMargin = endStartMargins
-            bottomMargin = endStartMargins
+            topMargin =
+                    (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
+            bottomMargin =
+                    (contextualButtonHeight + contentPadding + roundedCornerContentMargin).toInt()
             marginEnd = 0
             marginStart = 0
         }
 
-        navButtonContainer.layoutParams = navContainerParams
-        navButtonContainer.gravity = Gravity.CENTER
+        // Ensure order of buttons is correct
+        navButtonContainer.removeAllViews()
+        navButtonContainer.orientation = LinearLayout.VERTICAL
 
         addThreeButtons()
 
+        navButtonContainer.layoutParams = navContainerParams
+        navButtonContainer.gravity = Gravity.CENTER
+
         // Add the spaces in between the nav buttons
-        val spaceInBetween: Int =
-            resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
-        navButtonContainer.children.forEachIndexed { i, navButton ->
+        val spaceInBetween = (navButtonContainerHeight - homeButtonHeight -
+                sideButtonHeight * 2) / 2.0f
+        for (i in 0 until navButtonContainer.childCount) {
+            val navButton = navButtonContainer.getChildAt(i)
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
-            buttonLayoutParams.weight = 1f
+            val margin = (spaceInBetween / 2).toInt()
             when (i) {
                 0 -> {
-                    buttonLayoutParams.bottomMargin = spaceInBetween / 2
+                    // First button
+                    buttonLayoutParams.bottomMargin = margin
+                    buttonLayoutParams.height = sideButtonHeight.toInt()
                 }
                 navButtonContainer.childCount - 1 -> {
-                    buttonLayoutParams.topMargin = spaceInBetween / 2
+                    // Last button
+                    buttonLayoutParams.topMargin = margin
+                    buttonLayoutParams.height = sideButtonHeight.toInt()
                 }
                 else -> {
-                    buttonLayoutParams.bottomMargin = spaceInBetween / 2
-                    buttonLayoutParams.topMargin = spaceInBetween / 2
+                    // other buttons
+                    buttonLayoutParams.topMargin = margin
+                    buttonLayoutParams.bottomMargin = margin
+                    buttonLayoutParams.height = homeButtonHeight
                 }
             }
         }
 
-        repositionContextualButtons()
+        repositionContextualButtons(contextualButtonHeight.toInt())
     }
 
     open fun addThreeButtons() {
@@ -100,13 +120,17 @@
         navButtonContainer.addView(backButton)
     }
 
-    open fun repositionContextualButtons() {
+    open fun repositionContextualButtons(buttonSize: Int) {
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val contextualMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_contextual_button_padding)
-        repositionContextualContainer(startContextualContainer, contextualMargin, Gravity.TOP)
+        val roundedCornerContentMargin = resources.getDimensionPixelSize(
+                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
+        repositionContextualContainer(startContextualContainer, buttonSize,
+                roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
+        repositionContextualContainer(endContextualContainer, buttonSize,
+                0, roundedCornerContentMargin + contentPadding, Gravity.BOTTOM)
 
         if (imeSwitcher != null) {
             startContextualContainer.addView(imeSwitcher)
@@ -114,22 +138,24 @@
         }
         if (a11yButton != null) {
             startContextualContainer.addView(a11yButton)
+            a11yButton.layoutParams = getParamsToCenterView()
         }
         if (rotationButton != null) {
             startContextualContainer.addView(rotationButton.currentView)
             rotationButton.currentView.layoutParams = getParamsToCenterView()
         }
+        endContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
     }
 
-    override fun repositionContextualContainer(contextualContainer: ViewGroup, barAxisMargin: Int,
+    override fun repositionContextualContainer(contextualContainer: ViewGroup, buttonSize: Int,
+                                               barAxisMarginTop: Int, barAxisMarginBottom: Int,
                                                gravity: Int) {
-        val contextualContainerParams = FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+        val contextualContainerParams = FrameLayout.LayoutParams(MATCH_PARENT, buttonSize)
         contextualContainerParams.apply {
             marginStart = 0
             marginEnd = 0
-            topMargin = barAxisMargin
-            bottomMargin = barAxisMargin
+            topMargin = barAxisMarginTop
+            bottomMargin = barAxisMarginBottom
         }
         contextualContainerParams.gravity = gravity or Gravity.CENTER_HORIZONTAL
         contextualContainer.layoutParams = contextualContainerParams
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index e1ffa4d..0672270 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -19,13 +19,13 @@
 import android.content.res.Resources
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
-import com.android.launcher3.DeviceProfile
+import android.widget.Space
 import com.android.launcher3.R
-import com.android.launcher3.taskbar.TaskbarManager
-import com.android.launcher3.util.DimensionUtils
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.systemui.shared.rotation.RotationButton
 
 class PhonePortraitNavLayoutter(
@@ -36,6 +36,7 @@
         imeSwitcher: ImageView?,
         rotationButton: RotationButton?,
         a11yButton: ImageView?,
+        space: Space?
 ) :
     AbstractNavButtonLayoutter(
             resources,
@@ -44,30 +45,38 @@
             startContextualContainer,
             imeSwitcher,
             rotationButton,
-            a11yButton
+            a11yButton,
+            space
     ) {
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
-        // TODO(b/230395757): Polish pending, this is just to make it usable
-        val taskbarDimensions =
-            DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
-                    TaskbarManager.isPhoneMode(dp))
-        val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
+        val totalWidth = context.deviceProfile.widthPx
+        val homeButtonWidth = resources.getDimensionPixelSize(R.dimen.taskbar_phone_home_button_size)
+        val roundedCornerContentMargin = resources.getDimensionPixelSize(
+                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
+        val contentWidth = totalWidth - roundedCornerContentMargin * 2 - contentPadding * 2
+
+        // left:back:space(reserved for home):overview:right = 0.25:0.5:1:0.5:0.25
+        val contextualButtonWidth = contentWidth / (0.25f + 0.5f + 1f + 0.5f + 0.25f) * 0.25f
+        val sideButtonWidth = contextualButtonWidth * 2
+        val navButtonContainerWidth = contentWidth - contextualButtonWidth * 2
+
+        val navContainerParams = FrameLayout.LayoutParams(navButtonContainerWidth.toInt(),
+                ViewGroup.LayoutParams.MATCH_PARENT)
+        navContainerParams.apply {
+            topMargin = 0
+            bottomMargin = 0
+            marginEnd =
+                    (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+            marginStart =
+                    (contextualButtonWidth + contentPadding + roundedCornerContentMargin).toInt()
+        }
 
         // Ensure order of buttons is correct
         navButtonContainer.removeAllViews()
         navButtonContainer.orientation = LinearLayout.HORIZONTAL
 
-        val navContainerParams = FrameLayout.LayoutParams(
-                taskbarDimensions.x, ViewGroup.LayoutParams.MATCH_PARENT)
-        navContainerParams.apply {
-            topMargin = 0
-            bottomMargin = 0
-            marginEnd = endStartMargins
-            marginStart = endStartMargins
-        }
-
-        // Swap recents and back button in case we were landscape prior to this
         navButtonContainer.addView(backButton)
         navButtonContainer.addView(homeButton)
         navButtonContainer.addView(recentsButton)
@@ -76,25 +85,28 @@
         navButtonContainer.gravity = Gravity.CENTER
 
         // Add the spaces in between the nav buttons
-        val spaceInBetween =
-            resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
+        val spaceInBetween = (navButtonContainerWidth - homeButtonWidth -
+                sideButtonWidth * 2) / 2.0f
         for (i in 0 until navButtonContainer.childCount) {
             val navButton = navButtonContainer.getChildAt(i)
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
-            buttonLayoutParams.weight = 1f
+            val margin = (spaceInBetween / 2).toInt()
             when (i) {
                 0 -> {
                     // First button
-                    buttonLayoutParams.marginEnd = spaceInBetween / 2
+                    buttonLayoutParams.marginEnd = margin
+                    buttonLayoutParams.width = sideButtonWidth.toInt()
                 }
                 navButtonContainer.childCount - 1 -> {
                     // Last button
-                    buttonLayoutParams.marginStart = spaceInBetween / 2
+                    buttonLayoutParams.marginStart = margin
+                    buttonLayoutParams.width = sideButtonWidth.toInt()
                 }
                 else -> {
                     // other buttons
-                    buttonLayoutParams.marginStart = spaceInBetween / 2
-                    buttonLayoutParams.marginEnd = spaceInBetween / 2
+                    buttonLayoutParams.marginStart = margin
+                    buttonLayoutParams.marginEnd = margin
+                    buttonLayoutParams.width = homeButtonWidth
                 }
             }
         }
@@ -102,16 +114,19 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val contextualMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_contextual_button_padding)
-        repositionContextualContainer(endContextualContainer, contextualMargin, Gravity.END)
+        repositionContextualContainer(startContextualContainer, contextualButtonWidth.toInt(),
+                roundedCornerContentMargin + contentPadding, 0, Gravity.START)
+        repositionContextualContainer(endContextualContainer, contextualButtonWidth.toInt(), 0,
+                roundedCornerContentMargin + contentPadding, Gravity.END)
 
+        startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
         if (imeSwitcher != null) {
             endContextualContainer.addView(imeSwitcher)
             imeSwitcher.layoutParams = getParamsToCenterView()
         }
         if (a11yButton != null) {
             endContextualContainer.addView(a11yButton)
+            a11yButton.layoutParams = getParamsToCenterView()
         }
         if (rotationButton != null) {
             endContextualContainer.addView(rotationButton.currentView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
index 0368b1d..869cc43 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneSeascapeNavLayoutter.kt
@@ -19,8 +19,10 @@
 import android.content.res.Resources
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.Space
 import com.android.launcher3.R
 import com.android.systemui.shared.rotation.RotationButton
 
@@ -31,7 +33,8 @@
         startContextualContainer: ViewGroup,
         imeSwitcher: ImageView?,
         rotationButton: RotationButton?,
-        a11yButton: ImageView?
+        a11yButton: ImageView?,
+        space: Space?
 ) :
         PhoneLandscapeNavLayoutter(
                 resources,
@@ -40,7 +43,8 @@
                 startContextualContainer,
                 imeSwitcher,
                 rotationButton,
-                a11yButton
+                a11yButton,
+                space
         ) {
 
     override fun addThreeButtons() {
@@ -50,20 +54,26 @@
         navButtonContainer.addView(recentsButton)
     }
 
-    override fun repositionContextualButtons() {
+    override fun repositionContextualButtons(buttonSize: Int) {
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val contextualMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_contextual_button_padding)
-        repositionContextualContainer(endContextualContainer, contextualMargin, Gravity.BOTTOM)
+        val roundedCornerContentMargin = resources.getDimensionPixelSize(
+                R.dimen.taskbar_phone_rounded_corner_content_margin)
+        val contentPadding = resources.getDimensionPixelSize(R.dimen.taskbar_phone_content_padding)
+        repositionContextualContainer(startContextualContainer, buttonSize,
+                roundedCornerContentMargin + contentPadding, 0, Gravity.TOP)
+        repositionContextualContainer(endContextualContainer, buttonSize, 0,
+                roundedCornerContentMargin + contentPadding,  Gravity.BOTTOM)
 
+        startContextualContainer.addView(space, MATCH_PARENT, MATCH_PARENT)
         if (imeSwitcher != null) {
             endContextualContainer.addView(imeSwitcher)
             imeSwitcher.layoutParams = getParamsToCenterView()
         }
         if (a11yButton != null) {
             endContextualContainer.addView(a11yButton)
+            a11yButton.layoutParams = getParamsToCenterView()
         }
         if (rotationButton != null) {
             endContextualContainer.addView(rotationButton.currentView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index abdd32c..8eff95c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -19,50 +19,94 @@
 import android.content.res.Resources
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.Space
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.systemui.shared.rotation.RotationButton
 
+const val SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95
+const val SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05
+
 class SetupNavLayoutter(
-        resources: Resources,
-        navButtonContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?
+    resources: Resources,
+    navButtonsView: NearestTouchFrame,
+    navButtonContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    rotationButton: RotationButton?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
     AbstractNavButtonLayoutter(
-            resources,
-            navButtonContainer,
-            endContextualContainer,
-            startContextualContainer,
-            imeSwitcher,
-            rotationButton,
-            a11yButton
+        resources,
+        navButtonContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        rotationButton,
+        a11yButton,
+        space
     ) {
+    private val mNavButtonsView = navButtonsView
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         // Since setup wizard only has back button enabled, it looks strange to be
         // end-aligned, so start-align instead.
         val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
-        navButtonsLayoutParams.apply {
-            marginStart = navButtonsLayoutParams.marginEnd
-            marginEnd = 0
-            gravity = Gravity.START
+        val navButtonsViewLayoutParams = mNavButtonsView.layoutParams as FrameLayout.LayoutParams
+        val deviceProfile: DeviceProfile = context.deviceProfile
+
+        navButtonsLayoutParams.marginEnd = 0
+        navButtonsLayoutParams.gravity = Gravity.START
+        context.setTaskbarWindowSize(context.setupWindowSize)
+
+        // If SUW is on a large screen device that is landscape (or has a square aspect
+        // ratio) the back button has to be placed accordingly
+        if (
+            deviceProfile.isTablet && deviceProfile.isLandscape ||
+                (deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND &&
+                    deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND)
+        ) {
+            navButtonsLayoutParams.marginStart =
+                resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_start_margin)
+            navButtonsViewLayoutParams.bottomMargin =
+                resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_bottom_margin)
+            navButtonsLayoutParams.height =
+                resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_height)
+        } else {
+            val phoneOrPortraitSetupMargin =
+                resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
+            navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
+            navButtonsLayoutParams.bottomMargin =
+                if (!deviceProfile.isLandscape) 0
+                else
+                    phoneOrPortraitSetupMargin -
+                        resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
+            navButtonsViewLayoutParams.height =
+                resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
         }
-        navButtonContainer.requestLayout()
+        mNavButtonsView.layoutParams = navButtonsViewLayoutParams
+        navButtonContainer.layoutParams = navButtonsLayoutParams
 
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        val contextualMargin = resources.getDimensionPixelSize(
-                R.dimen.taskbar_contextual_button_padding)
-        repositionContextualContainer(endContextualContainer, 0, Gravity.END)
-        repositionContextualContainer(startContextualContainer, contextualMargin, Gravity.START)
+        val contextualMargin =
+            resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_padding)
+        repositionContextualContainer(endContextualContainer, WRAP_CONTENT, 0, 0, Gravity.END)
+        repositionContextualContainer(
+            startContextualContainer,
+            WRAP_CONTENT,
+            contextualMargin,
+            contextualMargin,
+            Gravity.START
+        )
 
         if (imeSwitcher != null) {
             startContextualContainer.addView(imeSwitcher)
@@ -70,6 +114,7 @@
         }
         if (a11yButton != null) {
             endContextualContainer.addView(a11yButton)
+            a11yButton.layoutParams = getParamsToCenterView()
         }
         if (rotationButton != null) {
             endContextualContainer.addView(rotationButton.currentView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index f5a4c64..34d3fad 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -19,38 +19,48 @@
 import android.content.res.Resources
 import android.view.Gravity
 import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
 import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
-import com.android.launcher3.DeviceProfile
+import android.widget.Space
 import com.android.launcher3.R
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.systemui.shared.rotation.RotationButton
 
-/**
- * Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode.
- */
+/** Layoutter for rendering task bar in large screen, both in 3-button and gesture nav mode. */
 class TaskbarNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup,
-        imeSwitcher: ImageView?,
-        rotationButton: RotationButton?,
-        a11yButton: ImageView?
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup,
+    imeSwitcher: ImageView?,
+    rotationButton: RotationButton?,
+    a11yButton: ImageView?,
+    space: Space?
 ) :
     AbstractNavButtonLayoutter(
-            resources,
-            navBarContainer,
-            endContextualContainer,
-            startContextualContainer,
-            imeSwitcher,
-            rotationButton,
-            a11yButton
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer,
+        imeSwitcher,
+        rotationButton,
+        a11yButton,
+        space
     ) {
 
-    override fun layoutButtons(dp: DeviceProfile, isA11yButtonPersistent: Boolean) {
+    override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
         // Add spacing after the end of the last nav button
-        var navMarginEnd = resources.getDimension(dp.inv.inlineNavButtonsEndSpacing).toInt()
+        var navMarginEnd =
+            resources.getDimension(context.deviceProfile.inv.inlineNavButtonsEndSpacing).toInt()
+
+        val cutout = context.display.cutout
+        val bottomRect = cutout?.boundingRectBottom
+        if (bottomRect != null && !bottomRect.isEmpty) {
+            navMarginEnd = bottomRect.width()
+        }
+
         val contextualWidth = endContextualContainer.width
         // If contextual buttons are showing, we check if the end margin is enough for the
         // contextual button to be showing - if not, move the nav buttons over a smidge
@@ -59,8 +69,11 @@
             navMarginEnd += resources.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing) / 2
         }
 
-        val navButtonParams = FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)
+        val navButtonParams =
+            FrameLayout.LayoutParams(
+                FrameLayout.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT
+            )
         navButtonParams.apply {
             gravity = Gravity.END or Gravity.CENTER_VERTICAL
             marginEnd = navMarginEnd
@@ -91,18 +104,38 @@
         endContextualContainer.removeAllViews()
         startContextualContainer.removeAllViews()
 
-        if (!dp.isGestureMode) {
-            val contextualMargin = resources.getDimensionPixelSize(
-                    R.dimen.taskbar_contextual_button_padding)
-            repositionContextualContainer(endContextualContainer, 0, Gravity.END)
-            repositionContextualContainer(startContextualContainer, contextualMargin, Gravity.START)
+        if (!context.deviceProfile.isGestureMode) {
+            val contextualMargin =
+                resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_padding)
+            repositionContextualContainer(endContextualContainer, WRAP_CONTENT, 0, 0, Gravity.END)
+            repositionContextualContainer(
+                startContextualContainer,
+                WRAP_CONTENT,
+                contextualMargin,
+                contextualMargin,
+                Gravity.START
+            )
 
             if (imeSwitcher != null) {
+                val imeStartMargin =
+                    resources.getDimensionPixelSize(
+                        R.dimen.taskbar_ime_switcher_button_margin_start
+                    )
                 startContextualContainer.addView(imeSwitcher)
-                imeSwitcher.layoutParams = getParamsToCenterView()
+                val imeSwitcherButtonParams =
+                    FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT
+                    )
+                imeSwitcherButtonParams.apply {
+                    marginStart = imeStartMargin
+                    gravity = Gravity.CENTER_VERTICAL
+                }
+                imeSwitcher.layoutParams = imeSwitcherButtonParams
             }
             if (a11yButton != null) {
                 endContextualContainer.addView(a11yButton)
+                a11yButton.layoutParams = getParamsToCenterView()
             }
             if (rotationButton != null) {
                 endContextualContainer.addView(rotationButton.currentView)
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index 432d272..9c3e8af 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -40,7 +40,6 @@
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 /** Root drag layer for the Taskbar overlay window. */
 public class TaskbarOverlayDragLayer extends
@@ -48,28 +47,6 @@
         ViewTreeObserver.OnComputeInternalInsetsListener {
 
     private SafeCloseable mViewCaptureCloseable;
-    private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
-    private final TouchController mClickListenerTouchController = new TouchController() {
-        @Override
-        public boolean onControllerTouchEvent(MotionEvent ev) {
-            if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
-                for (OnClickListener listener : mOnClickListeners) {
-                    listener.onClick(TaskbarOverlayDragLayer.this);
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-            for (int i = 0; i < getChildCount(); i++) {
-                if (isEventOverView(getChildAt(i), ev)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-    };
     private final List<TouchController> mTouchControllers = new ArrayList<>();
 
     TaskbarOverlayDragLayer(Context context) {
@@ -98,9 +75,6 @@
         List<TouchController> controllers = new ArrayList<>();
         controllers.add(mActivity.getDragController());
         controllers.addAll(mTouchControllers);
-        if (!mOnClickListeners.isEmpty()) {
-            controllers.add(mClickListenerTouchController);
-        }
         mControllers = controllers.toArray(new TouchController[0]);
     }
 
@@ -152,51 +126,6 @@
         mActivity.getOverlayController().maybeCloseWindow();
     }
 
-    /**
-     * Adds the given callback to clicks to this drag layer.
-     * <p>
-     * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
-     * outside the bounds of all child views.
-     * <p>
-     * If the click falls within the bounds of a child view, then this callback does not run and
-     * that child can optionally handle it.
-     */
-    private void addOnClickListener(@NonNull OnClickListener listener) {
-        boolean wasEmpty = mOnClickListeners.isEmpty();
-        mOnClickListeners.add(listener);
-        if (wasEmpty) {
-            recreateControllers();
-        }
-    }
-
-    /**
-     * Removes the given on click callback.
-     * <p>
-     * No-op if the callback was never added.
-     */
-    private void removeOnClickListener(@NonNull OnClickListener listener) {
-        boolean wasEmpty = mOnClickListeners.isEmpty();
-        mOnClickListeners.remove(listener);
-        if (!wasEmpty && mOnClickListeners.isEmpty()) {
-            recreateControllers();
-        }
-    }
-
-    /**
-     * Queues the given callback on the next click on this drag layer.
-     * <p>
-     * Once run, this callback is immediately removed.
-     */
-    public void runOnClickOnce(@NonNull OnClickListener listener) {
-        addOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                listener.onClick(v);
-                removeOnClickListener(this);
-            }
-        });
-    }
-
     /** Adds a {@link TouchController} to this drag layer. */
     public void addTouchController(@NonNull TouchController touchController) {
         mTouchControllers.add(touchController);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
deleted file mode 100644
index 4a26559..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import android.app.ActivityOptions;
-import android.app.Person;
-import android.content.Context;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.LauncherUserInfo;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.ColorDrawable;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.ArrayMap;
-import android.window.RemoteTransition;
-
-import com.android.launcher3.Flags;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.UserIconInfo;
-import com.android.quickstep.util.FadeOutRemoteTransition;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * A wrapper for the hidden API calls
- */
-public class ApiWrapper {
-
-    public static final boolean TASKBAR_DRAWN_IN_PROCESS = true;
-
-    public static Person[] getPersons(ShortcutInfo si) {
-        Person[] persons = si.getPersons();
-        return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons;
-    }
-
-    public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
-        return context.getSystemService(LauncherApps.class).getActivityOverrides();
-    }
-
-    /**
-     * Creates an ActivityOptions to play fade-out animation on closing targets
-     */
-    public static ActivityOptions createFadeOutAnimOptions(Context context) {
-        ActivityOptions options = ActivityOptions.makeBasic();
-        options.setRemoteTransition(new RemoteTransition(new FadeOutRemoteTransition()));
-        return options;
-    }
-
-    /**
-     * Returns a map of all users on the device to their corresponding UI properties
-     */
-    public static Map<UserHandle, UserIconInfo> queryAllUsers(Context context) {
-        UserManager um = context.getSystemService(UserManager.class);
-        Map<UserHandle, UserIconInfo> users = new ArrayMap<>();
-        List<UserHandle> usersActual = um.getUserProfiles();
-        if (usersActual != null) {
-            for (UserHandle user : usersActual) {
-                if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) {
-                    LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
-                    LauncherUserInfo launcherUserInfo = launcherApps.getLauncherUserInfo(user);
-                    // UserTypes not supported in Launcher are deemed to be the current
-                    // Foreground User.
-                    int userType = switch (launcherUserInfo.getUserType()) {
-                        case UserManager.USER_TYPE_PROFILE_MANAGED -> UserIconInfo.TYPE_WORK;
-                        case UserManager.USER_TYPE_PROFILE_CLONE -> UserIconInfo.TYPE_CLONED;
-                        case UserManager.USER_TYPE_PROFILE_PRIVATE -> UserIconInfo.TYPE_PRIVATE;
-                        default -> UserIconInfo.TYPE_MAIN;
-                    };
-                    long serial = launcherUserInfo.getUserSerialNumber();
-                    users.put(user, new UserIconInfo(user, userType, serial));
-                } else {
-                    long serial = um.getSerialNumberForUser(user);
-
-                    // Simple check to check if the provided user is work profile
-                    // TODO: Migrate to a better platform API
-                    NoopDrawable d = new NoopDrawable();
-                    boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user));
-                    UserIconInfo info = new UserIconInfo(
-                            user,
-                            isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN,
-                            serial);
-                    users.put(user, info);
-                }
-            }
-        }
-        return users;
-    }
-
-    private static class NoopDrawable extends ColorDrawable {
-        @Override
-        public int getIntrinsicHeight() {
-            return 1;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return 1;
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index e2f4f32..2eced74 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -16,11 +16,13 @@
 
 package com.android.launcher3.uioverrides;
 
+import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.app.animation.Interpolators.AGGRESSIVE_EASE_IN_OUT;
 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.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
@@ -110,7 +112,8 @@
         boolean exitingOverview = !FeatureFlags.enableSplitContextually() && !toState.overviewUi;
         if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
             setter.add(mRecentsView.getSplitSelectController().getSplitAnimationController()
-                    .createPlaceholderDismissAnim(mLauncher));
+                    .createPlaceholderDismissAnim(mLauncher, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
+                            setter.getDuration()));
             setter.setViewAlpha(
                     mRecentsView.getSplitInstructionsView(),
                     0,
@@ -132,15 +135,17 @@
         LauncherState fromState = mLauncher.getStateManager().getState();
         setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
                 toState.showTaskThumbnailSplash() ? 1f : 0f,
-                !toState.showTaskThumbnailSplash() && fromState == QUICK_SWITCH_FROM_HOME
-                        ? LINEAR : INSTANT);
+                getOverviewInterpolator(fromState, toState));
 
-        boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
-        Interpolator gridProgressInterpolator = showAsGrid
-                ? fromState == QUICK_SWITCH_FROM_HOME ? LINEAR : INSTANT
-                : FINAL_FRAME;
-        setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
-                gridProgressInterpolator);
+        setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS,
+                toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f,
+                getOverviewInterpolator(fromState, toState));
+    }
+
+    private Interpolator getOverviewInterpolator(LauncherState fromState, LauncherState toState) {
+        return fromState == QUICK_SWITCH_FROM_HOME
+                ? ACCELERATE_DECELERATE
+                : toState.overviewUi ? INSTANT : FINAL_FRAME;
     }
 
     abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
deleted file mode 100644
index 8f1d319..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.R;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-
-/** A util class that inflates a predicted app icon */
-public class PredictedAppIconInflater {
-    public static View inflate(LayoutInflater inflater, ViewGroup parent, WorkspaceItemInfo info) {
-        PredictedAppIcon icon = (PredictedAppIcon) inflater.inflate(
-                R.layout.predicted_app_icon, parent, false);
-        icon.applyFromWorkspaceItem(info);
-        return icon;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
index 6659fa0..45813ce 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
@@ -25,6 +25,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Executors;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 
@@ -55,7 +56,10 @@
 
     @Override
     public void onAppWidgetRemoved(int appWidgetId) {
-        mAppWidgetRemovedCallback.accept(appWidgetId);
+        // Route the call via model thread, in case it comes while a loader-bind is in progress
+        Executors.MODEL_EXECUTOR.execute(
+                () -> Executors.MAIN_EXECUTOR.execute(
+                        () -> mAppWidgetRemovedCallback.accept(appWidgetId)));
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 8092582..039c0a0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.uioverrides;
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_WIDGET_ATTEMPT;
 
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -27,10 +28,8 @@
 import android.util.Pair;
 import android.view.View;
 import android.widget.RemoteViews;
-import android.widget.Toast;
 import android.window.SplashScreen;
 
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
@@ -58,9 +57,11 @@
             return RemoteViews.startPendingIntent(hostView, pendingIntent,
                     remoteResponse.getLaunchOptions(view));
         }
-        if (mLauncher.isSplitSelectionEnabled()) {
-            Toast.makeText(hostView.getContext(), R.string.split_widgets_not_supported,
-                    Toast.LENGTH_SHORT).show();
+        if (mLauncher.isSplitSelectionActive()) {
+            // Log metric
+            StatsLogManager.StatsLogger logger = mLauncher.getStatsLogManager().logger();
+            logger.log(LAUNCHER_SPLIT_WIDGET_ATTEMPT);
+            mLauncher.handleIncorrectSplitTargetSelection();
             return true;
         }
         Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 9438e00..4acddee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -21,6 +21,9 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
+import static com.android.launcher3.Flags.enablePredictiveBackGesture;
+import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
@@ -35,11 +38,17 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
+import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
 import static com.android.launcher3.popup.SystemShortcut.INSTALL;
+import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
+import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP;
 import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX;
@@ -51,9 +60,11 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
@@ -64,7 +75,6 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.res.Configuration;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.hardware.display.DisplayManager;
@@ -72,18 +82,20 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
 import android.view.View;
 import android.widget.AnalogClock;
 import android.widget.TextClock;
 import android.window.BackEvent;
 import android.window.OnBackAnimationCallback;
 import android.window.OnBackInvokedDispatcher;
+import android.window.RemoteTransition;
 import android.window.SplashScreen;
 
 import androidx.annotation.BinderThread;
@@ -94,7 +106,8 @@
 import com.android.app.viewcapture.SettingsAwareViewCapture;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.HomeTransitionController;
+import com.android.launcher3.Flags;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.LauncherState;
@@ -140,7 +153,6 @@
 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.ObjectWrapper;
@@ -166,9 +178,12 @@
 import com.android.quickstep.util.SplitToWorkspaceController;
 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
 import com.android.quickstep.util.TISBindHelper;
+import com.android.quickstep.util.unfold.LauncherUnfoldTransitionController;
+import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -188,18 +203,15 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
-public class QuickstepLauncher extends Launcher {
+public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
     private static final boolean TRACE_LAYOUTS =
             SystemProperties.getBoolean("persist.debug.trace_layouts", false);
     private static final String TRACE_RELAYOUT_CLASS =
             SystemProperties.get("persist.debug.trace_request_layout_class", null);
-
-    private static final String TAG = "QuickstepLauncher";
-
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
 
     protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t";
@@ -207,9 +219,10 @@
     private FixedContainerItems mAllAppsPredictions;
     private HotseatPredictionController mHotseatPredictionController;
     private DepthController mDepthController;
-    private DesktopVisibilityController mDesktopVisibilityController;
+    private @Nullable DesktopVisibilityController mDesktopVisibilityController;
     private QuickstepTransitionManager mAppTransitionManager;
-    private OverviewActionsView mActionsView;
+
+    private OverviewActionsView<?> mActionsView;
     private TISBindHelper mTISBindHelper;
     private @Nullable LauncherTaskbarUIController mTaskbarUIController;
     // Will be updated when dragging from taskbar.
@@ -233,21 +246,25 @@
 
     private boolean mEnableWidgetDepth;
 
-    private HomeTransitionController mHomeTransitionController;
+    private boolean mIsPredictiveBackToHomeInProgress;
+
+    public static QuickstepLauncher getLauncher(Context context) {
+        return fromContext(context);
+    }
 
     @Override
     protected void setupViews() {
         super.setupViews();
 
         mActionsView = findViewById(R.id.overview_actions_view);
-        RecentsView overviewPanel = getOverviewPanel();
+        RecentsView<?,?> overviewPanel = getOverviewPanel();
         SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
         mSplitSelectStateController =
                 new SplitSelectStateController(this, mHandler, getStateManager(),
                         getDepthController(), getStatsLogManager(),
                         systemUiProxy, RecentsModel.INSTANCE.get(this),
                         () -> onStateBack());
-        if (isDesktopModeSupported()) {
+        if (enableDesktopWindowingMode()) {
             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
                     getStateManager(), systemUiProxy, getIApplicationThread(),
                     getDepthController());
@@ -265,15 +282,10 @@
         mAppTransitionManager.registerRemoteAnimations();
         mAppTransitionManager.registerRemoteTransitions();
 
-        if (FeatureFlags.enableHomeTransitionListener()) {
-            mHomeTransitionController = new HomeTransitionController(this);
-            mHomeTransitionController.registerHomeTransitionListener();
-        }
-
         mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
         mDepthController = new DepthController(this);
-        mDesktopVisibilityController = new DesktopVisibilityController(this);
-        if (isDesktopModeSupported()) {
+        if (enableDesktopWindowingMode()) {
+            mDesktopVisibilityController = new DesktopVisibilityController(this);
             mDesktopVisibilityController.registerSystemUiListener();
             mSplitSelectStateController.initSplitFromDesktopController(this);
         }
@@ -361,11 +373,19 @@
     public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
         // Only pause is taskbar controller is not present until the transition (if it exists) ends
         mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
+        PredictionRowView<?> predictionRowView =
+                getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class);
+        // Pause the prediction row updates until the transition (if it exists) ends.
+        predictionRowView.setPredictionUiUpdatePaused(true);
         RunnableList result = super.startActivitySafely(v, intent, item);
         if (result == null) {
             mHotseatPredictionController.setPauseUIUpdate(false);
+            predictionRowView.setPredictionUiUpdatePaused(false);
         } else {
-            result.add(() -> mHotseatPredictionController.setPauseUIUpdate(false));
+            result.add(() -> {
+                mHotseatPredictionController.setPauseUIUpdate(false);
+                predictionRowView.setPredictionUiUpdatePaused(false);
+            });
         }
         return result;
     }
@@ -414,6 +434,15 @@
         shortcuts.addAll(getSplitShortcuts());
         shortcuts.add(WIDGETS);
         shortcuts.add(INSTALL);
+        if (Flags.enablePrivateSpaceInstallShortcut()) {
+            shortcuts.add(PRIVATE_PROFILE_INSTALL);
+        }
+        if (Flags.enableShortcutDontSuggestApp()) {
+            shortcuts.add(DONT_SUGGEST_APP);
+        }
+        if (Flags.enablePrivateSpace()) {
+            shortcuts.add(UNINSTALL_APP);
+        }
         return shortcuts.stream();
     }
 
@@ -456,7 +485,6 @@
 
     @Override
     public void bindExtraContainerItems(FixedContainerItems item) {
-        Log.d(TAG, "Bind extra container items");
         if (item.containerId == Favorites.CONTAINER_PREDICTION) {
             mAllAppsPredictions = item;
             PredictionRowView<?> predictionRowView =
@@ -464,7 +492,6 @@
                             PredictionRowView.class);
             predictionRowView.setPredictedApps(item.items);
         } else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
-            Log.d(TAG, "Bind extra container item is hotseat prediction");
             mHotseatPredictionController.setPredictedItems(item);
         } else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) {
             getPopupDataProvider().setRecommendedWidgets(item.items);
@@ -483,6 +510,7 @@
             mAppTransitionManager.onActivityDestroyed();
         }
         mAppTransitionManager = null;
+        mIsPredictiveBackToHomeInProgress = false;
 
         if (mUnfoldTransitionProgressProvider != null) {
             SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
@@ -495,10 +523,6 @@
             mLauncherUnfoldAnimationController.onDestroy();
         }
 
-        if (mHomeTransitionController != null) {
-            mHomeTransitionController.unregisterHomeTransitionListener();
-        }
-
         if (mDesktopVisibilityController != null) {
             mDesktopVisibilityController.unregisterSystemUiListener();
         }
@@ -565,9 +589,10 @@
 
         ArrayList<TouchController> list = new ArrayList<>();
         list.add(getDragController());
-        Consumer<AnimatorSet> splitAnimator = animatorSet ->
+        BiConsumer<AnimatorSet, Long> splitAnimator = (animatorSet, duration) ->
                 animatorSet.play(mSplitSelectStateController.getSplitAnimationController()
-                        .createPlaceholderDismissAnim(this));
+                        .createPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
+                                duration));
         switch (mode) {
             case NO_BUTTON:
                 list.add(new NoButtonQuickSwitchTouchController(this));
@@ -616,10 +641,13 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        if (Utilities.ATLEAST_U && FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) {
+        // Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
+        // work, we must opt-in BEFORE registering back dispatcher. So we need to call
+        // setEnableOnBackInvokedCallback() before super.onCreate()
+        if (Utilities.ATLEAST_U && enablePredictiveBackGesture()) {
             getApplicationInfo().setEnableOnBackInvokedCallback(true);
         }
+        super.onCreate(savedInstanceState);
         if (savedInstanceState != null) {
             mPendingSplitSelectInfo = ObjectWrapper.unwrap(
                     savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO));
@@ -636,6 +664,14 @@
     }
 
     @Override
+    protected boolean initDeviceProfile(InvariantDeviceProfile idp) {
+        final boolean ret = super.initDeviceProfile(idp);
+        mDeviceProfile.isPredictiveBackSwipe =
+                getApplicationInfo().isOnBackInvokedCallbackEnabled();
+        return ret;
+    }
+
+    @Override
     public void startSplitSelection(SplitSelectSource splitSelectSource) {
         RecentsView recentsView = getOverviewPanel();
         // Check if there is already an instance of this app running, if so, initiate the split
@@ -644,12 +680,12 @@
                 Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
                 false /* findExactPairMatch */,
                 foundTasks -> {
-                    @Nullable Task foundTask = foundTasks.get(0);
+                    @Nullable Task foundTask = foundTasks[0];
                     boolean taskWasFound = foundTask != null;
                     splitSelectSource.alreadyRunningTaskId = taskWasFound
                             ? foundTask.key.id
                             : INVALID_TASK_ID;
-                    if (FeatureFlags.enableSplitContextually()) {
+                    if (enableSplitContextually()) {
                         startSplitToHome(splitSelectSource);
                     } else {
                         recentsView.initiateSplitSelect(splitSelectSource);
@@ -702,10 +738,14 @@
     }
 
     @Override
-    public boolean isSplitSelectionEnabled() {
+    public boolean isSplitSelectionActive() {
         return mSplitSelectStateController.isSplitSelectActive();
     }
 
+    public boolean areBothSplitAppsConfirmed() {
+        return mSplitSelectStateController.isBothSplitAppsConfirmed();
+    }
+
     @Override
     public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
         if (mTaskbarUIController != null) {
@@ -730,12 +770,14 @@
 
         super.onPause();
 
-        if (FeatureFlags.enableSplitContextually()) {
+        if (enableSplitContextually()) {
             // If Launcher pauses before both split apps are selected, exit split screen.
             if (!mSplitSelectStateController.isBothSplitAppsConfirmed() &&
                     !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) {
+                mSplitSelectStateController
+                        .logExitReason(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
                 mSplitSelectStateController.getSplitAnimationController()
-                        .playPlaceholderDismissAnim(this);
+                        .playPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
             }
         }
     }
@@ -800,8 +842,30 @@
     }
 
     @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        return tryHandleBackKey(event) || super.dispatchKeyEvent(event);
+    }
+
+    // TODO (b/267248420) Once the recents input consumer has been removed, there is no need to
+    //  handle the back key specially.
+    private boolean tryHandleBackKey(KeyEvent event) {
+        // Unlike normal activity, recents can receive input event from InputConsumer, so the input
+        // event won't go through ViewRootImpl#InputStage#onProcess.
+        // So when receive back key, try to do the same check thing in
+        // ViewRootImpl#NativePreImeInputStage#onProcess
+        if (!Utilities.ATLEAST_U || !enablePredictiveBackGesture()
+                || event.getKeyCode() != KeyEvent.KEYCODE_BACK
+                || event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
+            return false;
+        }
+
+        getOnBackAnimationCallback().onBackInvoked();
+        return true;
+    }
+
+    @Override
     protected void registerBackDispatcher() {
-        if (!FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get()) {
+        if (!enablePredictiveBackGesture()) {
             super.registerBackDispatcher();
             return;
         }
@@ -902,15 +966,13 @@
 
     @Override
     public void setResumed() {
-        if (isDesktopModeSupported()) {
-            DesktopVisibilityController controller = mDesktopVisibilityController;
-            if (controller != null && controller.areFreeformTasksVisible()
-                    && !controller.isRecentsGestureInProgress()) {
-                // Return early to skip setting activity to appear as resumed
-                // TODO(b/255649902): shouldn't be needed when we have a separate launcher state
-                //  for desktop that we can use to control other parts of launcher
-                return;
-            }
+        if (!enableDesktopWindowingWallpaperActivity()
+                && mDesktopVisibilityController != null
+                && mDesktopVisibilityController.areDesktopTasksVisible()
+                && !mDesktopVisibilityController.isRecentsGestureInProgress()) {
+            // Return early to skip setting activity to appear as resumed
+            // TODO: b/333533253 - Remove after flag rollout
+            return;
         }
         super.setResumed();
     }
@@ -937,6 +999,7 @@
         if (taskbarManager != null) {
             taskbarManager.setActivity(this);
         }
+        mTISBindHelper.setPredictiveBackToHomeInProgress(mIsPredictiveBackToHomeInProgress);
     }
 
     @Override
@@ -945,9 +1008,17 @@
     }
 
     private void initUnfoldTransitionProgressProvider() {
-        final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
-        if (config.isEnabled()) {
-            initRemotelyCalculatedUnfoldAnimation(config);
+        if (!enableUnfoldStateAnimation()) {
+            final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
+            if (config.isEnabled()) {
+                initRemotelyCalculatedUnfoldAnimation(config);
+            }
+        } else {
+            ProxyUnfoldTransitionProvider provider =
+                    SystemUiProxy.INSTANCE.get(this).getUnfoldTransitionProvider();
+            if (provider != null) {
+                new LauncherUnfoldTransitionController(this, provider);
+            }
         }
     }
 
@@ -1001,21 +1072,22 @@
     }
 
     @Override
-    protected void handleSplitAnimationGoingToHome() {
-        super.handleSplitAnimationGoingToHome();
+    protected void handleSplitAnimationGoingToHome(StatsLogManager.EventEnum splitDismissReason) {
+        super.handleSplitAnimationGoingToHome(splitDismissReason);
         mSplitSelectStateController.getSplitAnimationController()
-                .playPlaceholderDismissAnim(this);
+                .playPlaceholderDismissAnim(this, splitDismissReason);
     }
 
     @Override
-    public void dismissSplitSelection() {
-        super.dismissSplitSelection();
+    public void dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent) {
+        super.dismissSplitSelection(splitDismissEvent);
         mSplitSelectStateController.getSplitAnimationController()
-                .playPlaceholderDismissAnim(this);
+                .playPlaceholderDismissAnim(this, splitDismissEvent);
     }
 
-    public <T extends OverviewActionsView> T getActionsView() {
-        return (T) mActionsView;
+    @Override
+    public OverviewActionsView<?> getActionsView() {
+        return mActionsView;
     }
 
     @Override
@@ -1035,6 +1107,7 @@
         return mDepthController;
     }
 
+    @Nullable
     public DesktopVisibilityController getDesktopVisibilityController() {
         return mDesktopVisibilityController;
     }
@@ -1062,21 +1135,11 @@
         // populating workspace.
         // TODO: Find a better place for this
         WellbeingModel.INSTANCE.get(this);
-    }
 
-    @Override
-    public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
-            int workspaceItemCount, boolean isBindSync) {
-        pendingTasks.add(() -> {
-            // This is added in pending task as we need to wait for views to be positioned
-            // correctly before registering them for the animation.
-            if (mLauncherUnfoldAnimationController != null) {
-                // This is needed in case items are rebound while the unfold animation is in
-                // progress.
-                mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded();
-            }
-        });
-        super.onInitialBindComplete(boundPages, pendingTasks, workspaceItemCount, isBindSync);
+        if (mLauncherUnfoldAnimationController != null) {
+            // This is needed in case items are rebound while the unfold animation is in progress.
+            mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded();
+        }
     }
 
     @Override
@@ -1105,13 +1168,14 @@
     @Override
     public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
         RunnableList callbacks = new RunnableList();
-        ActivityOptions options = ActivityOptions.makeCustomAnimation(
-                this, 0, 0, Color.TRANSPARENT,
-                Executors.MAIN_EXECUTOR.getHandler(), null,
-                elapsedRealTime -> callbacks.executeAllAndDestroy());
+        ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
         options.setSplashScreenStyle(splashScreenStyle);
         options.setPendingIntentBackgroundActivityStartMode(
                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+
+        IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
+        options.setOnAnimationAbortListener(endCallback);
+        options.setOnAnimationFinishedListener(endCallback);
         return new ActivityOptionsWrapper(options, callbacks);
     }
 
@@ -1146,6 +1210,7 @@
         switch (info.container) {
             case Favorites.CONTAINER_DESKTOP:
             case Favorites.CONTAINER_HOTSEAT:
+            case Favorites.CONTAINER_PRIVATESPACE:
                 // Fall through and continue it's on the workspace (we don't support swiping back
                 // to other containers like all apps or the hotseat predictions (which can change)
                 break;
@@ -1242,10 +1307,18 @@
         mPendingSplitSelectInfo = null;
     }
 
+    /**
+     * Sets flag whether a predictive back-to-home animation is in progress
+     */
+    public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
+        mIsPredictiveBackToHomeInProgress = isInProgress;
+        mTISBindHelper.setPredictiveBackToHomeInProgress(isInProgress);
+    }
+
     @Override
-    public boolean areFreeformTasksVisible() {
+    public boolean areDesktopTasksVisible() {
         if (mDesktopVisibilityController != null) {
-            return mDesktopVisibilityController.areFreeformTasksVisible();
+            return mDesktopVisibilityController.areDesktopTasksVisible();
         }
         return false;
     }
@@ -1271,7 +1344,8 @@
     /**
      * Launches the given {@link GroupTask} in splitscreen.
      */
-    public void launchSplitTasks(@NonNull GroupTask groupTask) {
+    public void launchSplitTasks(
+            @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
         // Top/left and bottom/right tasks respectively.
         Task task1 = groupTask.task1;
         // task2 should never be null when calling this method. Allow a crash to catch invalid calls
@@ -1285,14 +1359,16 @@
                 /* freezeTaskList= */ false,
                 groupTask.mSplitBounds == null
                         ? SNAP_TO_50_50
-                        : groupTask.mSplitBounds.snapPosition);
+                        : groupTask.mSplitBounds.snapPosition,
+                remoteTransition);
     }
 
     /**
      * Launches two apps as an app pair.
      */
     public void launchAppPair(AppPairIcon appPairIcon) {
-        mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon);
+        mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon,
+                CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE);
     }
 
     public boolean canStartHomeSafely() {
@@ -1310,26 +1386,40 @@
         return (mTaskbarUIController != null && mTaskbarUIController.hasBubbles());
     }
 
-    private static final class LauncherTaskViewController extends
-            TaskViewTouchController<Launcher> {
+    @NonNull
+    public TISBindHelper getTISBindHelper() {
+        return mTISBindHelper;
+    }
 
-        LauncherTaskViewController(Launcher activity) {
+    @Override
+    public boolean handleIncorrectSplitTargetSelection() {
+        if (!enableSplitContextually() || !mSplitSelectStateController.isSplitSelectActive()) {
+            return false;
+        }
+        mSplitSelectStateController.getSplitInstructionsView().goBoing();
+        return true;
+    }
+
+    private static final class LauncherTaskViewController extends
+            TaskViewTouchController<QuickstepLauncher> {
+
+        LauncherTaskViewController(QuickstepLauncher activity) {
             super(activity);
         }
 
         @Override
         protected boolean isRecentsInteractive() {
-            return mActivity.isInState(OVERVIEW) || mActivity.isInState(OVERVIEW_MODAL_TASK);
+            return mContainer.isInState(OVERVIEW) || mContainer.isInState(OVERVIEW_MODAL_TASK);
         }
 
         @Override
         protected boolean isRecentsModal() {
-            return mActivity.isInState(OVERVIEW_MODAL_TASK);
+            return mContainer.isInState(OVERVIEW_MODAL_TASK);
         }
 
         @Override
         protected void onUserControlledAnimationCreated(AnimatorPlaybackController animController) {
-            mActivity.getStateManager().setCurrentUserControlledAnimation(animController);
+            mContainer.getStateManager().setCurrentUserControlledAnimation(animController);
         }
     }
 
@@ -1352,6 +1442,10 @@
         if (mHotseatPredictionController != null) {
             mHotseatPredictionController.dump(prefix, writer);
         }
+        PredictionRowView<?> predictionRowView =
+                getAppsView().getFloatingHeaderView().findFixedRowByType(
+                        PredictionRowView.class);
+        predictionRowView.dump(prefix, writer);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index f66bc60..01d5ff0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.uioverrides;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
@@ -26,18 +27,17 @@
 import android.util.SparseArray;
 import android.widget.RemoteViews;
 
+import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.LauncherWidgetHolder;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -67,13 +67,11 @@
 
     private static AppWidgetHost sWidgetHost = null;
 
-    private final SparseArray<AppWidgetHostView> mViews = new SparseArray<>();
-
+    private final UpdateHandler mUpdateHandler = this::onWidgetUpdate;
     private final @Nullable RemoteViews.InteractionHandler mInteractionHandler;
 
     private final @NonNull IntConsumer mAppWidgetRemovedCallback;
 
-    private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
     // Map to all pending updated keyed with appWidgetId;
     private final SparseArray<PendingUpdate> mPendingUpdateMap = new SparseArray<>();
 
@@ -103,7 +101,7 @@
                                     new ArrayList<>(h.mProviderChangedListeners).forEach(
                                     ProviderChangedListener::notifyWidgetProvidersChanged))),
                     UI_HELPER_EXECUTOR.getLooper());
-            if (!WidgetsModel.GO_DISABLE_WIDGETS) {
+            if (WIDGETS_ENABLED) {
                 sWidgetHost.startListening();
             }
         }
@@ -112,16 +110,12 @@
 
     @Override
     protected void updateDeferredView() {
-        super.updateDeferredView();
         int count = mPendingUpdateMap.size();
         for (int i = 0; i < count; i++) {
             int widgetId = mPendingUpdateMap.keyAt(i);
             AppWidgetHostView view = mViews.get(widgetId);
-            if (view == null) {
-                continue;
-            }
             PendingUpdate pendingUpdate = mPendingUpdateMap.valueAt(i);
-            if (pendingUpdate == null) {
+            if (view == null || pendingUpdate == null) {
                 continue;
             }
             if (pendingUpdate.providerInfo != null) {
@@ -172,7 +166,6 @@
     @Override
     public void deleteAppWidgetId(int appWidgetId) {
         super.deleteAppWidgetId(appWidgetId);
-        mViews.remove(appWidgetId);
         sListeners.remove(appWidgetId);
     }
 
@@ -182,7 +175,10 @@
     @Override
     public void destroy() {
         try {
-            MAIN_EXECUTOR.submit(() -> sHolders.remove(this)).get();
+            MAIN_EXECUTOR.submit(() -> {
+                clearViews();
+                sHolders.remove(this);
+            }).get();
         } catch (Exception e) {
             Log.e(TAG, "Failed to remove self from holder list", e);
         }
@@ -195,31 +191,11 @@
     }
 
     /**
-     * Add a listener that is triggered when the providers of the widgets are changed
-     * @param listener The listener that notifies when the providers changed
-     */
-    @Override
-    public void addProviderChangeListener(
-            @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
-        MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.add(listener));
-    }
-
-    /**
-     * Remove the specified listener from the host
-     * @param listener The listener that is to be removed from the host
-     */
-    @Override
-    public void removeProviderChangeListener(
-            LauncherWidgetHolder.ProviderChangedListener listener) {
-        MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.remove(listener));
-    }
-
-    /**
      * Stop the host from updating the widget views
      */
     @Override
     public void stopListening() {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return;
         }
 
@@ -227,46 +203,55 @@
         setListeningFlag(false);
     }
 
+    @Override
+    public SafeCloseable addOnUpdateListener(int appWidgetId,
+            LauncherAppWidgetProviderInfo appWidget, Runnable callback) {
+        UpdateHandler handler = new UpdateHandler() {
+            @Override
+            public <T> void onWidgetUpdate(int widgetId, UpdateKey<T> key, T data) {
+                if (KEY_VIEWS_UPDATE == key) {
+                    callback.run();
+                }
+            }
+        };
+        QuickstepWidgetHolderListener holderListener = getHolderListener(appWidgetId);
+        holderListener.addHolder(handler);
+        return () -> holderListener.mListeningHolders.remove(handler);
+    }
+
     /**
-     * Create a view for the specified app widget
-     * @param context The activity context for which the view is created
-     * @param appWidgetId The ID of the widget
-     * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
-     * @return A view for the widget
+     * Recycling logic:
+     * The holder doesn't maintain any states associated with the view, so if the view was
+     * initially initialized by this holder, all its state are already set in the view. We just
+     * update the RemoteViews for this view again, in case the widget sent an update during the
+     * time between inflation and recycle.
      */
+    @Override
+    protected LauncherAppWidgetHostView recycleExistingView(LauncherAppWidgetHostView view) {
+        RemoteViews views = getHolderListener(view.getAppWidgetId()).addHolder(mUpdateHandler);
+        view.updateAppWidget(views);
+        return view;
+    }
+
     @NonNull
     @Override
-    public LauncherAppWidgetHostView createView(@NonNull Context context, int appWidgetId,
-            @NonNull LauncherAppWidgetProviderInfo appWidget) {
-
-        if (appWidget.isCustomWidget()) {
-            LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
-            lahv.setAppWidget(appWidgetId, appWidget);
-            CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
-            return lahv;
-        }
-
-        LauncherAppWidgetHostView widgetView = getPendingView(appWidgetId);
-        if (widgetView != null) {
-            removePendingView(appWidgetId);
-        } else {
-            widgetView = new LauncherAppWidgetHostView(context);
-        }
-        widgetView.setIsWidgetCachingDisabled(true);
+    protected LauncherAppWidgetHostView createViewInternal(
+            int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+        LauncherAppWidgetHostView widgetView = new LauncherAppWidgetHostView(mContext);
         widgetView.setInteractionHandler(mInteractionHandler);
         widgetView.setAppWidget(appWidgetId, appWidget);
-        mViews.put(appWidgetId, widgetView);
+        widgetView.updateAppWidget(getHolderListener(appWidgetId).addHolder(mUpdateHandler));
+        return widgetView;
+    }
 
+    private static QuickstepWidgetHolderListener getHolderListener(int appWidgetId) {
         QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId);
         if (listener == null) {
             listener = new QuickstepWidgetHolderListener(appWidgetId);
             sWidgetHost.setListener(appWidgetId, listener);
             sListeners.put(appWidgetId, listener);
         }
-        RemoteViews remoteViews = listener.addHolder(this);
-        widgetView.updateAppWidget(remoteViews);
-
-        return widgetView;
+        return listener;
     }
 
     /**
@@ -276,15 +261,23 @@
     public void clearViews() {
         mViews.clear();
         for (int i = sListeners.size() - 1; i >= 0; i--) {
-            sListeners.valueAt(i).mListeningHolders.remove(this);
+            sListeners.valueAt(i).mListeningHolders.remove(mUpdateHandler);
         }
     }
 
+    /**
+     * Clears all the internal widget views excluding the update listeners
+     */
+    @Override
+    public void clearWidgetViews() {
+        mViews.clear();
+    }
+
     private static class QuickstepWidgetHolderListener
             implements AppWidgetHost.AppWidgetHostListener {
 
         // Static listeners should use a set that is backed by WeakHashMap to avoid memory leak
-        private final Set<QuickstepWidgetHolder> mListeningHolders = Collections.newSetFromMap(
+        private final Set<UpdateHandler> mListeningHolders = Collections.newSetFromMap(
                 new WeakHashMap<>());
 
         private final int mWidgetId;
@@ -297,27 +290,27 @@
 
         @UiThread
         @Nullable
-        public RemoteViews addHolder(@NonNull QuickstepWidgetHolder holder) {
+        public RemoteViews addHolder(@NonNull UpdateHandler holder) {
             mListeningHolders.add(holder);
             return mRemoteViews;
         }
 
         @Override
-        @WorkerThread
+        @AnyThread
         public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) {
             mRemoteViews = null;
             executeOnMainExecutor(KEY_PROVIDER_UPDATE, info);
         }
 
         @Override
-        @WorkerThread
+        @AnyThread
         public void updateAppWidget(@Nullable RemoteViews views) {
             mRemoteViews = views;
             executeOnMainExecutor(KEY_VIEWS_UPDATE, mRemoteViews);
         }
 
         @Override
-        @WorkerThread
+        @AnyThread
         public void onViewDataChanged(int viewId) {
             executeOnMainExecutor(KEY_VIEW_DATA_CHANGED, viewId);
         }
@@ -368,11 +361,15 @@
         }
     }
 
+    private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
+
+    private interface UpdateHandler {
+        <T> void onWidgetUpdate(int widgetId, UpdateKey<T> key, T data);
+    }
+
     private static class PendingUpdate {
         public final IntSet changedViews = new IntSet();
         public AppWidgetProviderInfo providerInfo;
         public RemoteViews remoteViews;
     }
-
-    private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 23e922c..6c1d4b1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -17,6 +17,7 @@
 
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
+import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
@@ -27,6 +28,7 @@
 import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_SPLIT_TRANSLATION;
 import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;
+import static com.android.wm.shell.Flags.enableSplitContextual;
 
 import android.animation.AnimatorSet;
 import android.annotation.TargetApi;
@@ -43,7 +45,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimUtils;
 import com.android.quickstep.util.SplitAnimationTimings;
 import com.android.quickstep.views.ClearAllButton;
@@ -67,6 +69,7 @@
         super.setState(state);
         if (state.overviewUi) {
             mRecentsView.updateEmptyMessage();
+        } else {
             mRecentsView.resetTaskVisuals();
         }
         setAlphas(PropertySetter.NO_ANIM_PROPERTY_SETTER, new StateAnimationConfig(), state);
@@ -120,24 +123,28 @@
      */
     private void handleSplitSelectionState(@NonNull LauncherState toState,
             @NonNull PendingAnimation builder, boolean animate) {
-        if (toState != OVERVIEW_SPLIT_SELECT) {
+        boolean goingToOverviewFromWorkspaceContextual = enableSplitContextual() &&
+                toState == OVERVIEW && mLauncher.isSplitSelectionActive();
+        if (toState != OVERVIEW_SPLIT_SELECT && !goingToOverviewFromWorkspaceContextual) {
             // Not going to split
             return;
         }
 
         // Create transition animations to split select
-        PagedOrientationHandler orientationHandler =
+        RecentsPagedOrientationHandler orientationHandler =
                 ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
-        Pair<FloatProperty, FloatProperty> taskViewsFloat =
+        Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
                 orientationHandler.getSplitSelectTaskOffset(
                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
                         mLauncher.getDeviceProfile());
 
         SplitAnimationTimings timings =
                 AnimUtils.getDeviceOverviewToSplitTimings(mLauncher.getDeviceProfile().isTablet);
-
-        mRecentsView.createSplitSelectInitAnimation(builder,
-                toState.getTransitionDuration(mLauncher, true /* isToState */));
+        if (!goingToOverviewFromWorkspaceContextual) {
+            // This animation is already done for the contextual case, don't redo it
+            mRecentsView.createSplitSelectInitAnimation(builder,
+                    toState.getTransitionDuration(mLauncher, true /* isToState */));
+        }
         // Shift tasks vertically downward to get out of placeholder view
         builder.setFloat(mRecentsView, taskViewsFloat.first,
                 toState.getSplitSelectTranslation(mLauncher),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
new file mode 100644
index 0000000..535b4c2
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides
+
+import android.app.ActivityOptions
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.LauncherActivityInfo
+import android.content.pm.LauncherApps
+import android.content.pm.ShortcutInfo
+import android.os.Flags.allowPrivateProfile
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.ArrayMap
+import android.window.RemoteTransition
+import com.android.launcher3.Flags.enablePrivateSpace
+import com.android.launcher3.Flags.enablePrivateSpaceInstallShortcut
+import com.android.launcher3.Flags.privateSpaceAppInstallerButton
+import com.android.launcher3.Flags.privateSpaceSysAppsSeparation
+import com.android.launcher3.Utilities
+import com.android.launcher3.proxy.ProxyActivityStarter
+import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.StartActivityParams
+import com.android.launcher3.util.UserIconInfo
+import com.android.quickstep.util.FadeOutRemoteTransition
+
+/** A wrapper for the hidden API calls */
+class SystemApiWrapper(context: Context?) : ApiWrapper(context) {
+
+    override fun getPersons(si: ShortcutInfo) = si.persons ?: Utilities.EMPTY_PERSON_ARRAY
+
+    override fun getActivityOverrides(): Map<String, LauncherActivityInfo> =
+        mContext.getSystemService(LauncherApps::class.java)!!.activityOverrides
+
+    override fun createFadeOutAnimOptions(): ActivityOptions =
+        ActivityOptions.makeBasic().apply {
+            remoteTransition = RemoteTransition(FadeOutRemoteTransition())
+        }
+
+    override fun queryAllUsers(): Map<UserHandle, UserIconInfo> {
+        if (!allowPrivateProfile() || !enablePrivateSpace()) {
+            return super.queryAllUsers()
+        }
+        val users = ArrayMap<UserHandle, UserIconInfo>()
+        mContext.getSystemService(UserManager::class.java)!!.userProfiles?.forEach { user ->
+            mContext.getSystemService(LauncherApps::class.java)!!.getLauncherUserInfo(user)?.apply {
+                users[user] =
+                    UserIconInfo(
+                        user,
+                        when (userType) {
+                            UserManager.USER_TYPE_PROFILE_MANAGED -> UserIconInfo.TYPE_WORK
+                            UserManager.USER_TYPE_PROFILE_CLONE -> UserIconInfo.TYPE_CLONED
+                            UserManager.USER_TYPE_PROFILE_PRIVATE -> UserIconInfo.TYPE_PRIVATE
+                            else -> UserIconInfo.TYPE_MAIN
+                        },
+                        userSerialNumber.toLong()
+                    )
+            }
+        }
+        return users
+    }
+
+    override fun getPreInstalledSystemPackages(user: UserHandle): List<String> =
+        if (allowPrivateProfile() && enablePrivateSpace() && privateSpaceSysAppsSeparation())
+            mContext
+                .getSystemService(LauncherApps::class.java)!!
+                .getPreInstalledSystemPackages(user)
+        else ArrayList()
+
+    override fun getAppMarketActivityIntent(packageName: String, user: UserHandle): Intent =
+        if (
+            allowPrivateProfile() &&
+                enablePrivateSpace() &&
+                (privateSpaceAppInstallerButton() || enablePrivateSpaceInstallShortcut())
+        )
+            ProxyActivityStarter.getLaunchIntent(
+                mContext,
+                StartActivityParams(null as PendingIntent?, 0).apply {
+                    intentSender =
+                        mContext
+                            .getSystemService(LauncherApps::class.java)!!
+                            .getAppMarketActivityIntent(packageName, user)
+                    options =
+                        ActivityOptions.makeBasic()
+                            .setPendingIntentBackgroundActivityStartMode(
+                                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                            )
+                            .toBundle()
+                    requireActivityResult = false
+                }
+            )
+        else super.getAppMarketActivityIntent(packageName, user)
+
+    /** Returns an intent which can be used to open Private Space Settings. */
+    override fun getPrivateSpaceSettingsIntent(): Intent? =
+        if (allowPrivateProfile() && enablePrivateSpace())
+            ProxyActivityStarter.getLaunchIntent(
+                mContext,
+                StartActivityParams(null as PendingIntent?, 0).apply {
+                    intentSender =
+                        mContext
+                            .getSystemService(LauncherApps::class.java)
+                            ?.privateSpaceSettingsIntent
+                            ?: return null
+                    options =
+                        ActivityOptions.makeBasic()
+                            .setPendingIntentBackgroundActivityStartMode(
+                                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+                            )
+                            .toBundle()
+                    requireActivityResult = false
+                }
+            )
+        else null
+
+    override fun isNonResizeableActivity(lai: LauncherActivityInfo) =
+        lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
deleted file mode 100644
index 630ef39..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.flags;
-
-import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.config.FeatureFlags.BooleanFlag;
-import com.android.launcher3.config.FeatureFlags.FlagState;
-
-class DebugFlag extends BooleanFlag {
-
-    public final String key;
-    public final String description;
-
-    @NonNull
-    public final FlagState defaultValue;
-
-    DebugFlag(String key, String description, FlagState defaultValue, boolean currentValue) {
-        super(currentValue);
-        this.key = key;
-        this.defaultValue = defaultValue;
-        this.description = description;
-    }
-
-    /**
-     * Returns {@code true} if this flag's value has been modified from its default.
-     * <p>
-     * This helps to identify which flags have been toggled in log dumps and bug reports to
-     * further help triaging and debugging.
-     */
-    boolean currentValueModified() {
-        switch (defaultValue) {
-            case ENABLED: return !get();
-            case TEAMFOOD: return TEAMFOOD_FLAG.get() != get();
-            case DISABLED: return get();
-            default: return true;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return key + ": defaultValue=" + defaultValue + ", mCurrentValue=" + get();
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
new file mode 100644
index 0000000..3881e9a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.uioverrides.flags
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.provider.DeviceConfig
+import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
+import android.text.Html
+import android.util.AttributeSet
+import android.view.inputmethod.EditorInfo
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.widget.doAfterTextChanged
+import androidx.preference.Preference
+import androidx.preference.PreferenceCategory
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceViewHolder
+import androidx.preference.SwitchPreference
+import com.android.launcher3.ExtendedEditText
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.R
+import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
+import com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN
+import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT
+import com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN
+import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
+import com.android.launcher3.util.PluginManagerWrapper
+import com.android.quickstep.util.DeviceConfigHelper
+import com.android.quickstep.util.DeviceConfigHelper.Companion.NAMESPACE_LAUNCHER
+import com.android.quickstep.util.DeviceConfigHelper.DebugInfo
+import com.android.systemui.shared.plugins.PluginEnabler
+import com.android.systemui.shared.plugins.PluginPrefs
+import java.util.Locale
+
+/** Helper class to generate UI for Device Config */
+class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, attr) {
+
+    init {
+        layoutResource = R.layout.developer_options_top_bar
+        isPersistent = false
+    }
+
+    override fun onBindViewHolder(holder: PreferenceViewHolder) {
+        super.onBindViewHolder(holder)
+
+        // Initialize search
+        (holder.findViewById(R.id.filter_box) as TextView?)?.doAfterTextChanged {
+            val query: String = it.toString().lowercase(Locale.getDefault()).replace("_", " ")
+            filterPreferences(query, this)
+        }
+    }
+
+    private fun filterPreferences(query: String, pg: PreferenceGroup) {
+        val count = pg.preferenceCount
+        var visible = false
+        for (i in 0 until count) {
+            val preference = pg.getPreference(i)
+            if (preference is PreferenceGroup) {
+                filterPreferences(query, preference)
+            } else {
+                val title =
+                    preference.title.toString().lowercase(Locale.getDefault()).replace("_", " ")
+                preference.isVisible = query.isEmpty() || title.contains(query)
+            }
+            visible = visible or preference.isVisible
+        }
+        pg.isVisible = visible
+    }
+
+    override fun onAttached() {
+        super.onAttached()
+
+        removeAll()
+        inflateServerFlags(newCategory("Server flags", "Long press to reset"))
+        if (PluginPrefs.hasPlugins(context)) {
+            inflatePluginPrefs(newCategory("Plugins"))
+        }
+        addIntentTargets()
+        addOnboardingPrefsCategory()
+    }
+
+    private fun newCategory(titleText: String, subTitleText: String? = null) =
+        PreferenceCategory(context).apply {
+            title = titleText
+            summary = subTitleText
+            this@DevOptionsUiHelper.addPreference(this)
+        }
+
+    /** Inflates preferences for all server flags in the provider PreferenceGroup */
+    private fun inflateServerFlags(parent: PreferenceGroup) {
+        val prefs = DeviceConfigHelper.prefs
+        // Sort the keys in the order of modified first followed by natural order
+        val allProps =
+            DeviceConfigHelper.allProps.values
+                .toList()
+                .sortedWith(
+                    Comparator.comparingInt { prop: DebugInfo<*> ->
+                            if (prefs.contains(prop.key)) 0 else 1
+                        }
+                        .thenComparing { prop: DebugInfo<*> -> prop.key }
+                )
+
+        // First add boolean flags
+        allProps.forEach {
+            if (it.isInt) return@forEach
+            val info = it as DebugInfo<Boolean>
+
+            val preference = CustomSwitchPref { holder, pref ->
+                holder.itemView.setOnLongClickListener {
+                    prefs.edit().remove(pref.key).apply()
+                    pref.setChecked(info.getBoolValue())
+                    summary = info.getSummary()
+                    true
+                }
+            }
+            preference.key = info.key
+            preference.isPersistent = false
+            preference.title = info.key
+            preference.summary = info.getSummary()
+            preference.setChecked(prefs.getBoolean(info.key, info.getBoolValue()))
+            preference.setOnPreferenceChangeListener { _, newVal ->
+                prefs.edit().putBoolean(info.key, newVal as Boolean).apply()
+                preference.summary = info.getSummary()
+                true
+            }
+            parent.addPreference(preference)
+        }
+
+        // Apply Int flags
+        allProps.forEach {
+            if (!it.isInt) return@forEach
+            val info = it as DebugInfo<Int>
+
+            val preference = CustomPref { holder, pref ->
+                val textView = holder.findViewById(R.id.pref_edit_text) as ExtendedEditText
+                textView.setText(info.getIntValueAsString())
+                textView.setOnEditorActionListener { _, actionId, _ ->
+                    if (actionId == EditorInfo.IME_ACTION_DONE) {
+                        prefs.edit().putInt(pref.key, textView.text.toString().toInt()).apply()
+                        pref.summary = info.getSummary()
+                        true
+                    }
+                    false
+                }
+                textView.setOnBackKeyListener {
+                    textView.setText(info.getIntValueAsString())
+                    true
+                }
+
+                holder.itemView.setOnLongClickListener {
+                    prefs.edit().remove(pref.key).apply()
+                    textView.setText(info.getIntValueAsString())
+                    pref.summary = info.getSummary()
+                    true
+                }
+            }
+            preference.key = info.key
+            preference.isPersistent = false
+            preference.title = info.key
+            preference.summary = info.getSummary()
+            preference.widgetLayoutResource = R.layout.develop_options_edit_text
+            parent.addPreference(preference)
+        }
+    }
+
+    /**
+     * Returns the summary to show the description and whether the flag overrides the default value.
+     */
+    private fun DebugInfo<*>.getSummary() =
+        Html.fromHtml(
+            (if (DeviceConfigHelper.prefs.contains(this.key))
+                "<font color='red'><b>[OVERRIDDEN]</b></font><br>"
+            else "") + this.desc
+        )
+
+    private fun DebugInfo<Boolean>.getBoolValue() =
+        DeviceConfigHelper.prefs.getBoolean(
+            this.key,
+            DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, this.key, this.valueInCode)
+        )
+
+    private fun DebugInfo<Int>.getIntValueAsString() =
+        DeviceConfigHelper.prefs
+            .getInt(this.key, DeviceConfig.getInt(NAMESPACE_LAUNCHER, this.key, this.valueInCode))
+            .toString()
+
+    /**
+     * Inflates the preferences for plugins
+     *
+     * A single pref is added for a plugin-group. A plugin-group is a collection of plugins in a
+     * single apk which have the same android:process tags defined. The apk should also hold the
+     * PLUGIN_PERMISSION. We collect all the plugin intents which Launcher listens for and fetch all
+     * corresponding plugins on the device. When a plugin-group is enabled/disabled we also need to
+     * notify the pluginManager manually since the broadcast-mechanism only works in sysui process
+     */
+    private fun inflatePluginPrefs(parent: PreferenceGroup) {
+        val manager = PluginManagerWrapper.INSTANCE[context] as PluginManagerWrapperImpl
+        val pm = context.packageManager
+
+        val pluginPermissionApps =
+            pm.getPackagesHoldingPermissions(
+                    arrayOf(PLUGIN_PERMISSION),
+                    PackageManager.MATCH_DISABLED_COMPONENTS
+                )
+                .map { it.packageName }
+
+        manager.pluginActions
+            .flatMap { action ->
+                pm.queryIntentServices(
+                        Intent(action),
+                        PackageManager.MATCH_DISABLED_COMPONENTS or
+                            PackageManager.GET_RESOLVED_FILTER
+                    )
+                    .filter { pluginPermissionApps.contains(it.serviceInfo.packageName) }
+            }
+            .groupBy { "${it.serviceInfo.packageName}-${it.serviceInfo.processName}" }
+            .values
+            .forEach { infoList ->
+                val pluginInfo = infoList[0]!!
+                val pluginUri = Uri.fromParts("package", pluginInfo.serviceInfo.packageName, null)
+
+                CustomSwitchPref { holder, _ ->
+                        holder.itemView.setOnLongClickListener {
+                            context.startActivity(
+                                Intent(ACTION_APPLICATION_DETAILS_SETTINGS, pluginUri)
+                            )
+                            true
+                        }
+                    }
+                    .apply {
+                        isPersistent = true
+                        title = pluginInfo.loadLabel(pm)
+                        isChecked =
+                            infoList.all {
+                                manager.pluginEnabler.isEnabled(it.serviceInfo.componentName)
+                            }
+                        summary =
+                            infoList
+                                .map { it.filter }
+                                .filter { it?.countActions() ?: 0 > 0 }
+                                .joinToString(prefix = "Plugins: ") {
+                                    it.getAction(0)
+                                        .replace("com.android.systemui.action.PLUGIN_", "")
+                                        .replace("com.android.launcher3.action.PLUGIN_", "")
+                                }
+
+                        setOnPreferenceChangeListener { _, newVal ->
+                            val disabledState =
+                                if (newVal as Boolean) PluginEnabler.ENABLED
+                                else PluginEnabler.DISABLED_MANUALLY
+                            infoList.forEach {
+                                manager.pluginEnabler.setDisabled(
+                                    it.serviceInfo.componentName,
+                                    disabledState
+                                )
+                            }
+                            manager.notifyChange(Intent(Intent.ACTION_PACKAGE_CHANGED, pluginUri))
+                            true
+                        }
+
+                        parent.addPreference(this)
+                    }
+            }
+    }
+
+    private fun addIntentTargets() {
+        val launchSandboxIntent =
+            Intent("com.android.quickstep.action.GESTURE_SANDBOX")
+                .setPackage(context.packageName)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        newCategory("Gesture Navigation Sandbox").apply {
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Gesture Tutorial Steps menu"
+                    intent = Intent(launchSandboxIntent).putExtra("use_tutorial_menu", true)
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Back Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("BACK_NAVIGATION"))
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Home Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("HOME_NAVIGATION"))
+                }
+            )
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Overview Tutorial"
+                    intent =
+                        Intent(launchSandboxIntent)
+                            .putExtra("use_tutorial_menu", false)
+                            .putExtra("tutorial_steps", arrayOf("OVERVIEW_NAVIGATION"))
+                }
+            )
+        }
+
+        newCategory("Other activity targets").apply {
+            addPreference(
+                Preference(context).apply {
+                    title = "Launch Secondary Display"
+                    intent =
+                        Intent(context, SecondaryDisplayLauncher::class.java)
+                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                }
+            )
+        }
+    }
+
+    private fun addOnboardingPrefsCategory() {
+        newCategory("Onboarding Flows").apply {
+            summary = "Reset these if you want to see the education again."
+            addOnboardPref(
+                "All Apps Bounce",
+                HOME_BOUNCE_SEEN.sharedPrefKey,
+                HOME_BOUNCE_COUNT.sharedPrefKey
+            )
+            addOnboardPref(
+                "Hybrid Hotseat Education",
+                HOTSEAT_DISCOVERY_TIP_COUNT.sharedPrefKey,
+                HOTSEAT_LONGPRESS_TIP_SEEN.sharedPrefKey
+            )
+            addOnboardPref("Taskbar Education", TASKBAR_EDU_TOOLTIP_STEP.sharedPrefKey)
+            addOnboardPref("All Apps Visited Count", ALL_APPS_VISITED_COUNT.sharedPrefKey)
+        }
+    }
+
+    private fun PreferenceCategory.addOnboardPref(title: String, vararg keys: String) =
+        this.addPreference(
+            Preference(context).also {
+                it.title = title
+                it.summary = "Tap to reset"
+                setOnPreferenceClickListener { _ ->
+                    LauncherPrefs.getPrefs(context)
+                        .edit()
+                        .apply { keys.forEach { key -> remove(key) } }
+                        .apply()
+                    Toast.makeText(context, "Reset $title", Toast.LENGTH_SHORT).show()
+                    true
+                }
+            }
+        )
+
+    private inner class CustomSwitchPref(
+        private val bindCallback: (holder: PreferenceViewHolder, pref: SwitchPreference) -> Unit
+    ) : SwitchPreference(context) {
+
+        override fun onBindViewHolder(holder: PreferenceViewHolder) {
+            super.onBindViewHolder(holder)
+            bindCallback.invoke(holder, this)
+        }
+    }
+
+    private inner class CustomPref(
+        private val bindCallback: (holder: PreferenceViewHolder, pref: Preference) -> Unit
+    ) : Preference(context) {
+
+        override fun onBindViewHolder(holder: PreferenceViewHolder) {
+            super.onBindViewHolder(holder)
+            bindCallback.invoke(holder, this)
+        }
+    }
+
+    companion object {
+        const val TAG = "DeviceConfigUIHelper"
+
+        const val PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN"
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
deleted file mode 100644
index c1a85fa..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.flags;
-
-import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
-import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
-import static com.android.launcher3.LauncherPrefs.PRIVATE_SPACE_APPS;
-import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_HIGHLIGHT_KEY;
-import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
-import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
-import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
-import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT;
-import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_LONGPRESS_TIP_SEEN;
-import static com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.provider.Settings;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.ArrayMap;
-import android.util.Pair;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceDataStore;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.PreferenceViewHolder;
-import androidx.preference.SeekBarPreference;
-import androidx.preference.SwitchPreference;
-
-import com.android.launcher3.ConstantItem;
-import com.android.launcher3.Flags;
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Dev-build only UI allowing developers to toggle flag settings and plugins.
- * See {@link FeatureFlags}.
- */
-public class DeveloperOptionsUI {
-
-    private static final String ACTION_PLUGIN_SETTINGS =
-            "com.android.systemui.action.PLUGIN_SETTINGS";
-    private static final String PLUGIN_PERMISSION = "com.android.systemui.permission.PLUGIN";
-
-    private final PreferenceFragmentCompat mFragment;
-    private final PreferenceScreen mPreferenceScreen;
-
-    private PreferenceCategory mPluginsCategory;
-
-    public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) {
-        mFragment = fragment;
-        mPreferenceScreen = fragment.getPreferenceScreen();
-
-        // Add search bar
-        View listView = mFragment.getListView();
-        ViewGroup parent = (ViewGroup) listView.getParent();
-        View topBar = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.developer_options_top_bar, parent, false);
-        parent.addView(topBar, parent.indexOfChild(listView));
-        initSearch(topBar.findViewById(R.id.filter_box));
-
-        new FlagTogglerPrefUi(mFragment.requireActivity(), topBar.findViewById(R.id.flag_apply_btn))
-                .applyTo(flags);
-
-        loadPluginPrefs();
-        maybeAddSandboxCategory();
-        addOnboardingPrefsCatergory();
-        if (FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()) {
-            addAllAppsFromOverviewCatergory();
-        }
-        addCustomLpnhCategory();
-        if (Flags.enablePrivateSpace()) {
-            addCustomPrivateAppsCategory();
-        }
-    }
-
-    private void filterPreferences(String query, PreferenceGroup pg) {
-        int count = pg.getPreferenceCount();
-        int hidden = 0;
-        for (int i = 0; i < count; i++) {
-            Preference preference = pg.getPreference(i);
-            if (preference instanceof PreferenceGroup) {
-                filterPreferences(query, (PreferenceGroup) preference);
-            } else {
-                String title = preference.getTitle().toString().toLowerCase().replace("_", " ");
-                if (query.isEmpty() || title.contains(query)) {
-                    preference.setVisible(true);
-                } else {
-                    preference.setVisible(false);
-                    hidden++;
-                }
-            }
-        }
-        pg.setVisible(hidden != count);
-    }
-
-    private void initSearch(EditText filterBox) {
-        filterBox.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { }
-
-            @Override
-            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { }
-
-            @Override
-            public void afterTextChanged(Editable editable) {
-                String query = editable.toString().toLowerCase().replace("_", " ");
-                filterPreferences(query, mPreferenceScreen);
-            }
-        });
-
-        if (mFragment.getArguments() != null) {
-            String filter = mFragment.getArguments().getString(EXTRA_FRAGMENT_HIGHLIGHT_KEY);
-            // Normally EXTRA_FRAGMENT_ARG_KEY is used to highlight the preference with the given
-            // key. This is a slight variation where we instead filter by the human-readable titles.
-            if (filter != null) {
-                filterBox.setText(filter);
-            }
-        }
-    }
-
-    private PreferenceCategory newCategory(String title) {
-        PreferenceCategory category = new PreferenceCategory(getContext());
-        category.setOrder(Preference.DEFAULT_ORDER);
-        category.setTitle(title);
-        mPreferenceScreen.addPreference(category);
-        return category;
-    }
-
-    private Context getContext() {
-        return mFragment.requireContext();
-    }
-
-    private void loadPluginPrefs() {
-        if (mPluginsCategory != null) {
-            mPreferenceScreen.removePreference(mPluginsCategory);
-        }
-        if (!PluginManagerWrapper.hasPlugins(getContext())) {
-            mPluginsCategory = null;
-            return;
-        }
-        mPluginsCategory = newCategory("Plugins");
-
-        PluginManagerWrapper manager = PluginManagerWrapper.INSTANCE.get(getContext());
-        Context prefContext = getContext();
-        PackageManager pm = getContext().getPackageManager();
-
-        Set<String> pluginActions = manager.getPluginActions();
-
-        ArrayMap<Pair<String, String>, ArrayList<Pair<String, ResolveInfo>>> plugins =
-                new ArrayMap<>();
-
-        Set<String> pluginPermissionApps = pm.getPackagesHoldingPermissions(
-                new String[]{PLUGIN_PERMISSION}, MATCH_DISABLED_COMPONENTS)
-                .stream()
-                .map(pi -> pi.packageName)
-                .collect(Collectors.toSet());
-
-        for (String action : pluginActions) {
-            String name = toName(action);
-            List<ResolveInfo> result = pm.queryIntentServices(
-                    new Intent(action), MATCH_DISABLED_COMPONENTS | GET_RESOLVED_FILTER);
-            for (ResolveInfo info : result) {
-                String packageName = info.serviceInfo.packageName;
-                if (!pluginPermissionApps.contains(packageName)) {
-                    continue;
-                }
-
-                Pair<String, String> key = Pair.create(packageName, info.serviceInfo.processName);
-                if (!plugins.containsKey(key)) {
-                    plugins.put(key, new ArrayList<>());
-                }
-                plugins.get(key).add(Pair.create(name, info));
-            }
-        }
-
-        PreferenceDataStore enabler = manager.getPluginEnabler();
-        plugins.forEach((key, si) -> {
-            String packageName = key.first;
-            List<ComponentName> componentNames = si.stream()
-                    .map(p -> new ComponentName(packageName, p.second.serviceInfo.name))
-                    .collect(Collectors.toList());
-            if (!componentNames.isEmpty()) {
-                SwitchPreference pref = new PluginPreference(
-                        prefContext, si.get(0).second, enabler, componentNames);
-                pref.setSummary("Plugins: "
-                        + si.stream().map(p -> p.first).collect(Collectors.joining(", ")));
-                mPluginsCategory.addPreference(pref);
-            }
-        });
-    }
-
-    private void maybeAddSandboxCategory() {
-        Context context = getContext();
-        if (context == null) {
-            return;
-        }
-        Intent launchSandboxIntent =
-                new Intent("com.android.quickstep.action.GESTURE_SANDBOX")
-                        .setPackage(context.getPackageName())
-                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        if (launchSandboxIntent.resolveActivity(context.getPackageManager()) == null) {
-            return;
-        }
-        PreferenceCategory sandboxCategory = newCategory("Gesture Navigation Sandbox");
-        sandboxCategory.setSummary("Learn and practice navigation gestures");
-        Preference launchTutorialStepMenuPreference = new Preference(context);
-        launchTutorialStepMenuPreference.setKey("launchTutorialStepMenu");
-        launchTutorialStepMenuPreference.setTitle("Launch Gesture Tutorial Steps menu");
-        launchTutorialStepMenuPreference.setSummary("Select a gesture tutorial step.");
-        launchTutorialStepMenuPreference.setIntent(
-                new Intent(launchSandboxIntent).putExtra("use_tutorial_menu", true));
-
-        sandboxCategory.addPreference(launchTutorialStepMenuPreference);
-        Preference launchOnboardingTutorialPreference = new Preference(context);
-        launchOnboardingTutorialPreference.setKey("launchOnboardingTutorial");
-        launchOnboardingTutorialPreference.setTitle("Launch Onboarding Tutorial");
-        launchOnboardingTutorialPreference.setSummary("Learn the basic navigation gestures.");
-        launchTutorialStepMenuPreference.setIntent(new Intent(launchSandboxIntent)
-                .putExtra("use_tutorial_menu", false)
-                .putExtra("tutorial_steps",
-                        new String[] {
-                                "HOME_NAVIGATION",
-                                "BACK_NAVIGATION",
-                                "OVERVIEW_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchOnboardingTutorialPreference);
-        Preference launchBackTutorialPreference = new Preference(context);
-        launchBackTutorialPreference.setKey("launchBackTutorial");
-        launchBackTutorialPreference.setTitle("Launch Back Tutorial");
-        launchBackTutorialPreference.setSummary("Learn how to use the Back gesture");
-        launchBackTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"BACK_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchBackTutorialPreference);
-        Preference launchHomeTutorialPreference = new Preference(context);
-        launchHomeTutorialPreference.setKey("launchHomeTutorial");
-        launchHomeTutorialPreference.setTitle("Launch Home Tutorial");
-        launchHomeTutorialPreference.setSummary("Learn how to use the Home gesture");
-        launchHomeTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"HOME_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchHomeTutorialPreference);
-        Preference launchOverviewTutorialPreference = new Preference(context);
-        launchOverviewTutorialPreference.setKey("launchOverviewTutorial");
-        launchOverviewTutorialPreference.setTitle("Launch Overview Tutorial");
-        launchOverviewTutorialPreference.setSummary("Learn how to use the Overview gesture");
-        launchOverviewTutorialPreference.setIntent(new Intent(launchSandboxIntent)
-                    .putExtra("use_tutorial_menu", false)
-                    .putExtra("tutorial_steps", new String[] {"OVERVIEW_NAVIGATION"}));
-
-        sandboxCategory.addPreference(launchOverviewTutorialPreference);
-        Preference launchSecondaryDisplayPreference = new Preference(context);
-        launchSecondaryDisplayPreference.setKey("launchSecondaryDisplay");
-        launchSecondaryDisplayPreference.setTitle("Launch Secondary Display");
-        launchSecondaryDisplayPreference.setSummary("Launch secondary display activity");
-        launchSecondaryDisplayPreference.setIntent(
-                new Intent(context, SecondaryDisplayLauncher.class));
-
-    }
-
-    private void addOnboardingPrefsCatergory() {
-        PreferenceCategory onboardingCategory = newCategory("Onboarding Flows");
-        onboardingCategory.setSummary("Reset these if you want to see the education again.");
-
-        onboardingCategory.addPreference(createOnboardPref("All Apps Bounce",
-                HOME_BOUNCE_SEEN.getSharedPrefKey(), HOME_BOUNCE_COUNT.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("Hybrid Hotseat Education",
-                HOTSEAT_DISCOVERY_TIP_COUNT.getSharedPrefKey(),
-                HOTSEAT_LONGPRESS_TIP_SEEN.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("Taskbar Education",
-                TASKBAR_EDU_TOOLTIP_STEP.getSharedPrefKey()));
-        onboardingCategory.addPreference(createOnboardPref("All Apps Visited Count",
-                ALL_APPS_VISITED_COUNT.getSharedPrefKey()));
-    }
-
-    private Preference createOnboardPref(String title, String... keys) {
-        Preference onboardingPref = new Preference(getContext());
-        onboardingPref.setTitle(title);
-        onboardingPref.setSummary("Tap to reset");
-        onboardingPref.setOnPreferenceClickListener(preference -> {
-            SharedPreferences.Editor sharedPrefsEdit = LauncherPrefs.getPrefs(getContext())
-                    .edit();
-            for (String key : keys) {
-                sharedPrefsEdit.remove(key);
-            }
-            sharedPrefsEdit.apply();
-            Toast.makeText(getContext(), "Reset " + title, Toast.LENGTH_SHORT).show();
-            return true;
-        });
-        return onboardingPref;
-    }
-
-    private void addAllAppsFromOverviewCatergory() {
-        PreferenceCategory category = newCategory("All Apps from Overview Config");
-        category.addPreference(createSeekBarPreference("Threshold to open All Apps from Overview",
-                105, 500, 100, ALL_APPS_OVERVIEW_THRESHOLD));
-    }
-
-    private void addCustomLpnhCategory() {
-        PreferenceCategory category = newCategory("Long Press Nav Handle Config");
-        if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
-            category.addPreference(createSeekBarPreference("Slop multiplier (applied to edge slop, "
-                            + "which is generally already 50% higher than touch slop)",
-                    25, 200, 100, LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE));
-            category.addPreference(createSeekBarPreference("Trigger milliseconds",
-                    100, 500, 1, LONG_PRESS_NAV_HANDLE_TIMEOUT_MS));
-        }
-        if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get()) {
-            category.addPreference(createSeekBarPreference("Haptic hint start scale",
-                    0, 100, 100, LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT));
-            category.addPreference(createSeekBarPreference("Haptic hint end scale",
-                    0, 100, 100, LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT));
-            category.addPreference(createSeekBarPreference("Haptic hint scale exponent",
-                    1, 5, 1, LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT));
-            category.addPreference(createSeekBarPreference("Haptic hint iterations (12 ms each)",
-                    0, 200, 1, LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS));
-            category.addPreference(createSeekBarPreference("Haptic hint delay (ms)",
-                    0, 400, 1, LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY));
-        }
-    }
-
-    private void addCustomPrivateAppsCategory() {
-        PreferenceCategory category = newCategory("Apps in Private Space Config");
-        category.addPreference(createSeekBarPreference(
-                "Number of Apps to put in private region", 0, 100, 1, PRIVATE_SPACE_APPS));
-    }
-
-    /**
-     * Create a preference with text and a seek bar. Should be added to a PreferenceCategory.
-     *
-     * @param title text to show for this seek bar
-     * @param min min value for the seek bar
-     * @param max max value for the seek bar
-     * @param scale how much to divide the value to convert int to float
-     * @param launcherPref used to store the current value
-     */
-    private SeekBarPreference createSeekBarPreference(String title, int min, int max, int scale,
-            ConstantItem<Integer> launcherPref) {
-        SeekBarPreference seekBarPref = new SeekBarPreference(getContext());
-        seekBarPref.setTitle(title);
-        seekBarPref.setSingleLineTitle(false);
-
-        seekBarPref.setMax(max);
-        seekBarPref.setMin(min);
-        seekBarPref.setUpdatesContinuously(true);
-        seekBarPref.setIconSpaceReserved(false);
-        // Don't directly save to shared prefs, use LauncherPrefs instead.
-        seekBarPref.setPersistent(false);
-        seekBarPref.setOnPreferenceChangeListener((preference, newValue) -> {
-            LauncherPrefs.get(getContext()).put(launcherPref, newValue);
-            preference.setSummary(String.valueOf(scale == 1 ? newValue
-                    : (int) newValue / (float) scale));
-            return true;
-        });
-        int value = LauncherPrefs.get(getContext()).get(launcherPref);
-        seekBarPref.setValue(value);
-        // For some reason the initial value is not triggering the summary update, so call manually.
-        seekBarPref.setSummary(String.valueOf(scale == 1 ? value
-                : value / (float) scale));
-        return seekBarPref;
-    }
-
-    private String toName(String action) {
-        String str = action.replace("com.android.systemui.action.PLUGIN_", "")
-                .replace("com.android.launcher3.action.PLUGIN_", "");
-        StringBuilder b = new StringBuilder();
-        for (String s : str.split("_")) {
-            if (b.length() != 0) {
-                b.append(' ');
-            }
-            b.append(s.substring(0, 1));
-            b.append(s.substring(1).toLowerCase());
-        }
-        return b.toString();
-    }
-
-    private static class PluginPreference extends SwitchPreference {
-        private final String mPackageName;
-        private final ResolveInfo mSettingsInfo;
-        private final PreferenceDataStore mPluginEnabler;
-        private final List<ComponentName> mComponentNames;
-
-        PluginPreference(Context prefContext, ResolveInfo pluginInfo,
-                PreferenceDataStore pluginEnabler, List<ComponentName> componentNames) {
-            super(prefContext);
-            PackageManager pm = prefContext.getPackageManager();
-            mPackageName = pluginInfo.serviceInfo.applicationInfo.packageName;
-            Intent settingsIntent = new Intent(ACTION_PLUGIN_SETTINGS).setPackage(mPackageName);
-            // If any Settings activity in app has category filters, set plugin action as category.
-            List<ResolveInfo> settingsInfos =
-                    pm.queryIntentActivities(settingsIntent, GET_RESOLVED_FILTER);
-            if (pluginInfo.filter != null) {
-                for (ResolveInfo settingsInfo : settingsInfos) {
-                    if (settingsInfo.filter != null && settingsInfo.filter.countCategories() > 0) {
-                        settingsIntent.addCategory(pluginInfo.filter.getAction(0));
-                        break;
-                    }
-                }
-            }
-
-            mSettingsInfo = pm.resolveActivity(settingsIntent, 0);
-            mPluginEnabler = pluginEnabler;
-            mComponentNames = componentNames;
-            setTitle(pluginInfo.loadLabel(pm));
-            setChecked(isPluginEnabled());
-            setWidgetLayoutResource(R.layout.switch_preference_with_settings);
-        }
-
-        private boolean isEnabled(ComponentName cn) {
-            return mPluginEnabler.getBoolean(pluginEnabledKey(cn), true);
-
-        }
-
-        private boolean isPluginEnabled() {
-            for (ComponentName componentName : mComponentNames) {
-                if (!isEnabled(componentName)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        @Override
-        protected boolean persistBoolean(boolean isEnabled) {
-            boolean shouldSendBroadcast = false;
-            for (ComponentName componentName : mComponentNames) {
-                if (isEnabled(componentName) != isEnabled) {
-                    mPluginEnabler.putBoolean(pluginEnabledKey(componentName), isEnabled);
-                    shouldSendBroadcast = true;
-                }
-            }
-            if (shouldSendBroadcast) {
-                final String pkg = mPackageName;
-                final Intent intent = new Intent(PLUGIN_CHANGED,
-                        pkg != null ? Uri.fromParts("package", pkg, null) : null);
-                getContext().sendBroadcast(intent);
-            }
-            setChecked(isEnabled);
-            return true;
-        }
-
-        @Override
-        public void onBindViewHolder(PreferenceViewHolder holder) {
-            super.onBindViewHolder(holder);
-            boolean hasSettings = mSettingsInfo != null;
-            holder.findViewById(R.id.settings).setVisibility(hasSettings ? VISIBLE : GONE);
-            holder.findViewById(R.id.divider).setVisibility(hasSettings ? VISIBLE : GONE);
-            holder.findViewById(R.id.settings).setOnClickListener(v -> {
-                if (hasSettings) {
-                    v.getContext().startActivity(new Intent().setComponent(
-                            new ComponentName(mSettingsInfo.activityInfo.packageName,
-                                    mSettingsInfo.activityInfo.name)));
-                }
-            });
-            holder.itemView.setOnLongClickListener(v -> {
-                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
-                intent.setData(Uri.fromParts("package", mPackageName, null));
-                getContext().startActivity(intent);
-                return true;
-            });
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
deleted file mode 100644
index 915f4ae..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.flags;
-
-import com.android.launcher3.config.FeatureFlags.FlagState;
-
-class DeviceFlag extends DebugFlag {
-
-    private final boolean mDefaultValueInCode;
-
-    DeviceFlag(String key, String description, FlagState defaultValue,
-            boolean currentValue, boolean defaultValueInCode) {
-        super(key, description, defaultValue, currentValue);
-        mDefaultValueInCode = defaultValueInCode;
-    }
-
-    @Override
-    boolean currentValueModified() {
-        return super.currentValueModified() || mDefaultValueInCode != get();
-    }
-
-    @Override
-    public String toString() {
-        return super.toString() + ", mDefaultValueInCode=" + mDefaultValueInCode;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
deleted file mode 100644
index ec0566a..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.flags;
-
-import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
-import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Process;
-import android.text.Html;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.Toast;
-
-import androidx.preference.PreferenceDataStore;
-import androidx.preference.PreferenceGroup;
-import androidx.preference.PreferenceViewHolder;
-import androidx.preference.SwitchPreference;
-
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
- */
-public final class FlagTogglerPrefUi implements ActivityLifecycleCallbacksAdapter {
-
-    private static final String TAG = "FlagTogglerPrefFrag";
-
-    private final View mFlagsApplyButton;
-    private final Context mContext;
-
-    private final PreferenceDataStore mDataStore = new PreferenceDataStore() {
-
-        @Override
-        public void putBoolean(String key, boolean value) {
-            FlagsFactory.getSharedPreferences().edit().putBoolean(key, value).apply();
-            updateMenu();
-        }
-
-        @Override
-        public boolean getBoolean(String key, boolean defaultValue) {
-            return FlagsFactory.getSharedPreferences().getBoolean(key, defaultValue);
-        }
-    };
-
-    public FlagTogglerPrefUi(Activity activity, View flagsApplyButton) {
-        mFlagsApplyButton = flagsApplyButton;
-        mContext = mFlagsApplyButton.getContext();
-        activity.registerActivityLifecycleCallbacks(this);
-
-        mFlagsApplyButton.setOnClickListener(v -> {
-            FlagsFactory.getSharedPreferences().edit().commit();
-            Log.e(TAG,
-                    "Killing launcher process " + Process.myPid() + " to apply new flag values");
-            System.exit(0);
-        });
-    }
-
-    public void applyTo(PreferenceGroup parent) {
-        Set<String> modifiedPrefs = FlagsFactory.getSharedPreferences().getAll().keySet();
-        List<DebugFlag> flags = FlagsFactory.getDebugFlags();
-        flags.sort((f1, f2) -> {
-            // Sort first by any prefs that the user has changed, then alphabetically.
-            int changeComparison = Boolean.compare(
-                    modifiedPrefs.contains(f2.key), modifiedPrefs.contains(f1.key));
-            return changeComparison != 0
-                    ? changeComparison
-                    : f1.key.compareToIgnoreCase(f2.key);
-        });
-
-        // Ensure that teamfood flag comes on the top
-        if (flags.remove(TEAMFOOD_FLAG)) {
-            flags.add(0, (DebugFlag) TEAMFOOD_FLAG);
-        }
-
-        // For flag overrides we only want to store when the engineer chose to override the
-        // flag with a different value than the default. That way, when we flip flags in
-        // future, engineers will pick up the new value immediately. To accomplish this, we use a
-        // custom preference data store.
-        for (DebugFlag flag : flags) {
-            SwitchPreference switchPreference = new SwitchPreference(mContext) {
-                @Override
-                public void onBindViewHolder(PreferenceViewHolder holder) {
-                    super.onBindViewHolder(holder);
-                    holder.itemView.setOnLongClickListener(v -> {
-                        FlagsFactory.getSharedPreferences().edit().remove(flag.key).apply();
-                        setChecked(getFlagStateFromSharedPrefs(flag));
-                        updateSummary(this, flag);
-                        updateMenu();
-                        return true;
-                    });
-                }
-            };
-            switchPreference.setKey(flag.key);
-            switchPreference.setDefaultValue(FlagsFactory.getEnabledValue(flag.defaultValue));
-            switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
-            switchPreference.setTitle(flag.key);
-            updateSummary(switchPreference, flag);
-            switchPreference.setPreferenceDataStore(mDataStore);
-            switchPreference.setOnPreferenceChangeListener((p, v) -> {
-                new Handler().post(() -> updateSummary(switchPreference, flag));
-                return true;
-            });
-
-
-            parent.addPreference(switchPreference);
-        }
-        updateMenu();
-    }
-
-    /**
-     * Updates the summary to show the description and whether the flag overrides the default value.
-     */
-    private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) {
-        String summary = flag.defaultValue == TEAMFOOD
-                ? "<font color='blue'><b>[TEAMFOOD]</b> </font>" : "";
-        if (FlagsFactory.getSharedPreferences().contains(flag.key)) {
-            summary += "<font color='red'><b>[OVERRIDDEN]</b> </font>";
-        }
-        if (!TextUtils.isEmpty(summary)) {
-            summary += "<br>";
-        }
-        switchPreference.setSummary(Html.fromHtml(summary + flag.description));
-    }
-
-    private void updateMenu() {
-        mFlagsApplyButton.setVisibility(anyChanged() ? View.VISIBLE : View.INVISIBLE);
-    }
-
-    @Override
-    public void onActivityStopped(Activity activity) {
-        if (anyChanged()) {
-            Toast.makeText(mContext, "Flag won't be applied until you restart launcher",
-                    Toast.LENGTH_LONG).show();
-        }
-    }
-
-    private boolean getFlagStateFromSharedPrefs(DebugFlag flag) {
-        boolean defaultValue = FlagsFactory.getEnabledValue(flag.defaultValue);
-        return mDataStore.getBoolean(flag.key, defaultValue);
-    }
-
-    private boolean anyChanged() {
-        for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
-            if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
deleted file mode 100644
index 48d313e..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.flags;
-
-import static android.app.ActivityThread.currentApplication;
-
-import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE;
-import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
-import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.provider.DeviceConfig;
-import android.provider.DeviceConfig.Properties;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.config.FeatureFlags.BooleanFlag;
-import com.android.launcher3.config.FeatureFlags.FlagState;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
-import com.android.launcher3.util.ScreenOnTracker;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Helper class to create various flags for system build
- */
-public class FlagsFactory {
-
-    private static final String TAG = "FlagsFactory";
-
-    private static final FlagsFactory INSTANCE = new FlagsFactory();
-    private static final boolean FLAG_AUTO_APPLY_ENABLED = true;
-
-    private static final String FLAGS_PREF_NAME = "featureFlags";
-    public static final String NAMESPACE_LAUNCHER = "launcher";
-
-    private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
-    private static final List<IntFlag> sIntFlags = new ArrayList<>();
-    private static SharedPreferences sSharedPreferences;
-
-    static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag(
-            0, "LAUNCHER_TEAMFOOD", DISABLED, "Enable this flag to opt-in all team food flags");
-
-    private final Set<String> mKeySet = new HashSet<>();
-    private boolean mRestartRequested = false;
-
-    private FlagsFactory() {
-        if (!FLAG_AUTO_APPLY_ENABLED) {
-            return;
-        }
-        DeviceConfig.addOnPropertiesChangedListener(
-                NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged);
-    }
-
-    static boolean getEnabledValue(FlagState flagState) {
-        if (IS_DEBUG_DEVICE) {
-            switch (flagState) {
-                case ENABLED:
-                    return true;
-                case TEAMFOOD:
-                    return TEAMFOOD_FLAG.get();
-                default:
-                    return false;
-            }
-        } else {
-            return flagState == ENABLED;
-        }
-    }
-
-    /**
-     * Creates a new debug flag. Debug flags always take their default value in release builds. On
-     * dogfood builds, they can be manually turned on using the flag toggle UI.
-     */
-    public static BooleanFlag getDebugFlag(
-            int bugId, String key, FlagState flagState, String description) {
-        if (IS_DEBUG_DEVICE) {
-            boolean defaultValue = getEnabledValue(flagState);
-            boolean currentValue = getSharedPreferences().getBoolean(key, defaultValue);
-            DebugFlag flag = new DebugFlag(key, description, flagState, currentValue);
-            sDebugFlags.add(flag);
-            return flag;
-        } else {
-            return new BooleanFlag(getEnabledValue(flagState));
-        }
-    }
-
-    /**
-     * Creates a new release flag. Release flags can be rolled out using server configurations and
-     * also allow manual overrides on debug builds.
-     */
-    public static BooleanFlag getReleaseFlag(
-            int bugId, String key, FlagState flagState, String description) {
-        INSTANCE.mKeySet.add(key);
-        boolean defaultValueInCode = getEnabledValue(flagState);
-        boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode);
-        if (IS_DEBUG_DEVICE) {
-            boolean currentValue = getSharedPreferences().getBoolean(key, defaultValue);
-            DebugFlag flag = new DeviceFlag(key, description,
-                    (defaultValue == defaultValueInCode) ? flagState
-                            : defaultValue ? ENABLED : DISABLED, currentValue, defaultValueInCode);
-            sDebugFlags.add(flag);
-            return flag;
-        } else {
-            return new BooleanFlag(defaultValue);
-        }
-    }
-
-    /**
-     * Creates a new integer flag. Integer flags are always release flags
-     */
-    public static IntFlag getIntFlag(
-            int bugId, String key, int defaultValueInCode, String description) {
-        INSTANCE.mKeySet.add(key);
-        int defaultValue = DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode);
-        if (IS_DEBUG_DEVICE) {
-            IntDeviceFlag flag = new IntDeviceFlag(key, defaultValue, defaultValueInCode);
-            sIntFlags.add(flag);
-            return flag;
-        } else {
-            return new IntFlag(defaultValue);
-        }
-    }
-
-    static List<DebugFlag> getDebugFlags() {
-        if (!IS_DEBUG_DEVICE) {
-            return Collections.emptyList();
-        }
-        synchronized (sDebugFlags) {
-            return new ArrayList<>(sDebugFlags);
-        }
-    }
-
-    /** Returns the SharedPreferences instance backing Debug FeatureFlags. */
-    @NonNull
-    static SharedPreferences getSharedPreferences() {
-        if (sSharedPreferences == null) {
-            sSharedPreferences = currentApplication()
-                    .createDeviceProtectedStorageContext()
-                    .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
-        }
-        return sSharedPreferences;
-    }
-
-    /**
-     * Dumps the current flags state to the print writer
-     */
-    public static void dump(PrintWriter pw) {
-        if (!IS_DEBUG_DEVICE) {
-            return;
-        }
-        pw.println("DeviceFlags:");
-        pw.println("  BooleanFlags:");
-        synchronized (sDebugFlags) {
-            for (DebugFlag flag : sDebugFlags) {
-                if (flag instanceof DeviceFlag) {
-                    pw.println((flag.currentValueModified() ? "  ->" : "    ") + flag);
-                }
-            }
-        }
-        pw.println("  IntFlags:");
-        synchronized (sIntFlags) {
-            for (IntFlag flag : sIntFlags) {
-                pw.println("    " + flag);
-            }
-        }
-        pw.println("  DebugFlags:");
-        synchronized (sDebugFlags) {
-            for (DebugFlag flag : sDebugFlags) {
-                if (!(flag instanceof DeviceFlag)) {
-                    pw.println((flag.currentValueModified() ? "  ->" : "    ") + flag);
-                }
-            }
-        }
-    }
-
-    private void onPropertiesChanged(Properties properties) {
-        if (!Collections.disjoint(properties.getKeyset(), mKeySet)) {
-            // Schedule a restart
-            if (mRestartRequested) {
-                return;
-            }
-            Log.e(TAG, "Flag changed, scheduling restart");
-            mRestartRequested = true;
-            ScreenOnTracker sot = ScreenOnTracker.INSTANCE.get(currentApplication());
-            if (sot.isScreenOn()) {
-                sot.addListener(this::onScreenOnChanged);
-            } else {
-                onScreenOnChanged(false);
-            }
-        }
-    }
-
-    private void onScreenOnChanged(boolean isOn) {
-        if (mRestartRequested && !isOn) {
-            Log.e(TAG, "Restart requested, killing process");
-            System.exit(0);
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
deleted file mode 100644
index 4f3b0ae..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDeviceFlag.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.flags;
-
-import com.android.launcher3.config.FeatureFlags.IntFlag;
-
-public class IntDeviceFlag extends IntFlag {
-    public final String key;
-    private final int mDefaultValueInCode;
-
-    public IntDeviceFlag(String key, int currentValue, int defaultValueInCode) {
-        super(currentValue);
-        this.key = key;
-        mDefaultValueInCode = defaultValueInCode;
-    }
-
-    @Override
-    public String toString() {
-        return key + ": mCurrentValue=" + get() + ", defaultValueInCode=" + mDefaultValueInCode;
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
index faa900b..4e09f1f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
@@ -18,12 +18,10 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 
-import androidx.preference.PreferenceDataStore;
-
 import com.android.launcher3.LauncherPrefs;
 import com.android.systemui.shared.plugins.PluginEnabler;
 
-public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnabler {
+public class PluginEnablerImpl implements PluginEnabler {
 
     private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
 
@@ -44,12 +42,12 @@
     }
 
     private void setState(ComponentName component, boolean enabled) {
-        putBoolean(pluginEnabledKey(component), enabled);
+        mSharedPrefs.edit().putBoolean(pluginEnabledKey(component), enabled).apply();
     }
 
     @Override
     public boolean isEnabled(ComponentName component) {
-        return getBoolean(pluginEnabledKey(component), true);
+        return mSharedPrefs.getBoolean(pluginEnabledKey(component), true);
     }
 
     @Override
@@ -57,17 +55,7 @@
         return isEnabled(componentName) ? ENABLED : DISABLED_MANUALLY;
     }
 
-    @Override
-    public void putBoolean(String key, boolean value) {
-        mSharedPrefs.edit().putBoolean(key, value).apply();
-    }
-
-    @Override
-    public boolean getBoolean(String key, boolean defValue) {
-        return mSharedPrefs.getBoolean(key, defValue);
-    }
-
-    static String pluginEnabledKey(ComponentName cn) {
+    private static String pluginEnabledKey(ComponentName cn) {
         return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
similarity index 71%
rename from quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
rename to quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
index 7f78713..74572c4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
@@ -1,15 +1,17 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package com.android.launcher3.uioverrides.plugins;
@@ -24,11 +26,10 @@
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
 
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.PluginListener;
-import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.shared.plugins.PluginActionManager;
 import com.android.systemui.shared.plugins.PluginInstance;
 import com.android.systemui.shared.plugins.PluginManagerImpl;
@@ -41,35 +42,30 @@
 import java.util.List;
 import java.util.Set;
 
-public class PluginManagerWrapper {
-
-    public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
-            new MainThreadInitializedObject<>(PluginManagerWrapper::new);
-
-    public static final String PLUGIN_CHANGED = PluginManager.PLUGIN_CHANGED;
+public class PluginManagerWrapperImpl extends PluginManagerWrapper {
 
     private static final UncaughtExceptionPreHandlerManager UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER =
             new UncaughtExceptionPreHandlerManager();
 
     private final Context mContext;
-    private final PluginManager mPluginManager;
+    private final PluginManagerImpl mPluginManager;
     private final PluginEnablerImpl mPluginEnabler;
 
-    private PluginManagerWrapper(Context c) {
+    public PluginManagerWrapperImpl(Context c) {
         mContext = c;
         mPluginEnabler = new PluginEnablerImpl(c);
         List<String> privilegedPlugins = Collections.emptyList();
         PluginInstance.Factory instanceFactory = new PluginInstance.Factory(
                 getClass().getClassLoader(), new PluginInstance.InstanceFactory<>(),
                 new PluginInstance.VersionCheckerImpl(), privilegedPlugins,
-                Utilities.IS_DEBUG_DEVICE);
+                BuildConfig.IS_DEBUG_DEVICE);
         PluginActionManager.Factory instanceManagerFactory = new PluginActionManager.Factory(
                 c, c.getPackageManager(), c.getMainExecutor(), MODEL_EXECUTOR,
                 c.getSystemService(NotificationManager.class), mPluginEnabler,
                 privilegedPlugins, instanceFactory);
 
         mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
-                Utilities.IS_DEBUG_DEVICE,
+                BuildConfig.IS_DEBUG_DEVICE,
                 UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER, mPluginEnabler,
                 new PluginPrefs(c), privilegedPlugins);
     }
@@ -78,18 +74,13 @@
         return mPluginEnabler;
     }
 
-    /** */
-    public <T extends Plugin> void addPluginListener(
-            PluginListener<T> listener, Class<T> pluginClass) {
-        addPluginListener(listener, pluginClass, false);
-    }
-
-    /** */
+    @Override
     public <T extends Plugin> void addPluginListener(
             PluginListener<T> listener, Class<T> pluginClass, boolean allowMultiple) {
         mPluginManager.addPluginListener(listener, pluginClass, allowMultiple);
     }
 
+    @Override
     public void removePluginListener(PluginListener<? extends Plugin> listener) {
         mPluginManager.removePluginListener(listener);
     }
@@ -98,17 +89,12 @@
         return new PluginPrefs(mContext).getPluginList();
     }
 
-    /**
-     * Returns the string key used to store plugin enabled/disabled setting
-     */
-    public static String pluginEnabledKey(ComponentName cn) {
-        return PluginEnablerImpl.pluginEnabledKey(cn);
+    /** Notifies that a plugin state has changed */
+    public void notifyChange(Intent intent) {
+        mPluginManager.onReceive(mContext, intent);
     }
 
-    public static boolean hasPlugins(Context context) {
-        return PluginPrefs.hasPlugins(context);
-    }
-
+    @Override
     public void dump(PrintWriter pw) {
         final List<ComponentName> enabledPlugins = new ArrayList<>();
         final List<ComponentName> disabledPlugins = new ArrayList<>();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 3767cce..2625919 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,10 +16,12 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
 
 import android.content.Context;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -27,6 +29,10 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.BaseDepthController;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+
+import java.util.concurrent.TimeUnit;
 
 /**
  * Definition for AllApps state
@@ -35,6 +41,8 @@
 
     private static final int STATE_FLAGS =
             FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS | FLAG_HOTSEAT_INACCESSIBLE;
+    private static final long BACK_CUJ_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
+
 
     public AllAppsState(int id) {
         super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
@@ -49,6 +57,46 @@
     }
 
     @Override
+    public void onBackStarted(Launcher launcher) {
+        // Because the back gesture can take longer time depending on when user release the finger,
+        // we pass BACK_CUJ_TIMEOUT_MS as timeout to the jank monitor.
+        InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
+                Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK, BACK_CUJ_TIMEOUT_MS);
+        super.onBackStarted(launcher);
+    }
+
+    @Override
+    public void onBackInvoked(Launcher launcher) {
+        // In predictive back swipe, onBackInvoked() will be called after onBackStarted().
+        // In 3 button mode, onBackStarted() is not called but onBackInvoked() will be called.
+        // Thus In onBackInvoked(), we should only begin instrumenting if we didn't call
+        // onBackStarted() to start instrumenting CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK.
+        if (!InteractionJankMonitorWrapper.isInstrumenting(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK)) {
+            InteractionJankMonitorWrapper.begin(
+                    launcher.getAppsView(), Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+        }
+        super.onBackInvoked(launcher);
+    }
+
+    /** Called when predictive back swipe is cancelled. */
+    @Override
+    public void onBackCancelled(Launcher launcher) {
+        super.onBackCancelled(launcher);
+        InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+    }
+
+    @Override
+    protected void onBackAnimationCompleted(boolean success) {
+        if (success) {
+            // Animation was successful.
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+        } else {
+            // Animation was canceled.
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+        }
+    }
+
+    @Override
     public String getDescription(Launcher launcher) {
         return launcher.getAppsView().getDescription();
     }
@@ -85,8 +133,14 @@
             return context.getDeviceProfile().bottomSheetDepth;
         } else {
             // The scrim fades in at approximately 50% of the swipe gesture.
-            // This means that the depth should be greater than 1, in order to fully zoom out.
-            return 2f;
+            if (enableScalingRevealHomeAnimation()) {
+                // This means that the depth should be twice of what we want, in order to fully zoom
+                // out during the visible portion of the animation.
+                return BaseDepthController.DEPTH_60_PERCENT;
+            } else {
+                // This means that the depth should be greater than 1, in order to fully zoom out.
+                return 2f;
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index d11a08b..7fa121d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -15,17 +15,17 @@
  */
 package com.android.launcher3.uioverrides.states;
 
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.content.Context;
 import android.graphics.Color;
 
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.quickstep.util.BaseDepthController;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 
@@ -62,7 +62,7 @@
 
     @Override
     public float[] getOverviewScaleAndOffset(Launcher launcher) {
-        return getOverviewScaleAndOffsetForBackgroundState(launcher);
+        return getOverviewScaleAndOffsetForBackgroundState(launcher.getOverviewPanel());
     }
 
     @Override
@@ -90,13 +90,14 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        if (isDesktopModeSupported()) {
-            if (Launcher.getLauncher(context).areFreeformTasksVisible()) {
-                // Don't blur the background while freeform tasks are visible
-                return 0;
-            }
+        if (Launcher.getLauncher(context).areDesktopTasksVisible()) {
+            // Don't blur the background while desktop tasks are visible
+            return BaseDepthController.DEPTH_0_PERCENT;
+        } else if (enableScalingRevealHomeAnimation()) {
+            return BaseDepthController.DEPTH_70_PERCENT;
+        } else {
+            return 1f;
         }
-        return 1;
     }
 
     @Override
@@ -123,9 +124,7 @@
     }
 
     public static float[] getOverviewScaleAndOffsetForBackgroundState(
-            BaseDraggingActivity activity) {
-        return new float[] {
-                ((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(),
-                NO_OFFSET};
+            RecentsView recentsView) {
+        return new float[] {recentsView.getMaxScaleForFullScreen(), NO_OFFSET};
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 1d55da3..3c291e6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -20,7 +20,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -51,7 +50,7 @@
 
     @Override
     public float[] getOverviewScaleAndOffset(Launcher launcher) {
-        return getOverviewScaleAndOffsetForModalState(launcher);
+        return getOverviewScaleAndOffsetForModalState(launcher.getOverviewPanel());
     }
 
     @Override
@@ -60,14 +59,8 @@
     }
 
     @Override
-    public void onBackPressed(Launcher launcher) {
+    public void onBackInvoked(Launcher launcher) {
         launcher.getStateManager().goToState(LauncherState.OVERVIEW);
-        RecentsView recentsView = launcher.<RecentsView>getOverviewPanel();
-        if (recentsView != null) {
-            recentsView.resetModalVisuals();
-        } else {
-            super.onBackPressed(launcher);
-        }
     }
 
     @Override
@@ -78,8 +71,7 @@
         return super.isTaskbarStashed(launcher);
     }
 
-    public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
-        RecentsView recentsView = activity.<RecentsView>getOverviewPanel();
+    public static float[] getOverviewScaleAndOffsetForModalState(RecentsView recentsView) {
         Rect taskSize = recentsView.getSelectedTaskBounds();
         Rect modalTaskSize = new Rect();
         recentsView.getModalTaskSize(modalTaskSize);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 396d0ab..d0eef8e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -16,7 +16,9 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
+import static com.android.wm.shell.Flags.enableSplitContextual;
 
 import android.content.Context;
 import android.graphics.Rect;
@@ -28,6 +30,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Themes;
+import com.android.quickstep.util.BaseDepthController;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -120,10 +123,22 @@
         if (showFloatingSearch) {
             elements |= FLOATING_SEARCH_BAR;
         }
+        if (enableSplitContextual() && launcher.isSplitSelectionActive()) {
+            elements &= ~CLEAR_ALL_BUTTON;
+        }
         return elements;
     }
 
     @Override
+    public float getSplitSelectTranslation(Launcher launcher) {
+        if (!enableSplitContextual() || !launcher.isSplitSelectionActive()) {
+            return 0f;
+        }
+        RecentsView recentsView = launcher.getOverviewPanel();
+        return recentsView.getSplitSelectTranslation();
+    }
+
+    @Override
     public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) {
         return areElementsVisible(launcher, FLOATING_SEARCH_BAR) ? 0
                 : super.getFloatingSearchBarRestingMarginBottom(launcher);
@@ -173,12 +188,18 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        //TODO revert when b/178661709 is fixed
-        return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
+        // TODO(178661709): revert to always scaled
+        if (enableScalingRevealHomeAnimation()) {
+            return SystemProperties.getBoolean("ro.launcher.depth.overview", true)
+                    ? BaseDepthController.DEPTH_70_PERCENT
+                    : BaseDepthController.DEPTH_0_PERCENT;
+        } else {
+            return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
+        }
     }
 
     @Override
-    public void onBackPressed(Launcher launcher) {
+    public void onBackInvoked(Launcher launcher) {
         RecentsView recentsView = launcher.getOverviewPanel();
         TaskView taskView = recentsView.getRunningTaskView();
         if (taskView != null) {
@@ -188,7 +209,7 @@
                 recentsView.snapToPage(recentsView.indexOfChild(taskView));
             }
         } else {
-            super.onBackPressed(launcher);
+            super.onBackInvoked(launcher);
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
index ba44d6a..dfad409 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.uioverrides.states;
 
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.graphics.Color;
 
@@ -46,11 +45,9 @@
 
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
-        if (isDesktopModeSupported()) {
-            if (launcher.areFreeformTasksVisible()) {
-                // No scrim while freeform tasks are visible
-                return Color.TRANSPARENT;
-            }
+        if (launcher.areDesktopTasksVisible()) {
+            // No scrim while desktop tasks are visible
+            return Color.TRANSPARENT;
         }
         DeviceProfile dp = launcher.getDeviceProfile();
         if (dp.isTaskbarPresentInApps) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 6651c73..0368f3a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -37,7 +37,6 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
-import static com.android.launcher3.QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
 import static com.android.launcher3.WorkspaceStateTransitionAnimation.getWorkspaceSpringScaleAnimator;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
@@ -55,14 +54,13 @@
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 
 import android.animation.ValueAnimator;
-import android.util.Log;
 
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.AllAppsSwipeController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
@@ -96,9 +94,7 @@
     @Override
     public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
             StateAnimationConfig config) {
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "creating animation fromState: "
-                + fromState + " toState: " + toState);
-        RecentsView overview = mActivity.getOverviewPanel();
+        RecentsView overview = mContainer.getOverviewPanel();
         if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) {
             overview.switchToScreenshot(() ->
                     overview.finishRecentsAnimation(true /* toRecents */, null));
@@ -110,15 +106,19 @@
                         clampToProgress(LINEAR, 0, 0.33f));
             }
 
+            // We sync the scrim fade with the taskbar animation duration to avoid any flickers for
+            // taskbar icons disappearing before hotseat icons show up.
+            float scrimUpperBoundFromSplit =
+                    QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
             config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
             config.setInterpolator(ANIM_SCRIM_FADE,
                     fromState == OVERVIEW_SPLIT_SELECT
-                            ? clampToProgress(LINEAR, 0.33f, 1)
+                            ? clampToProgress(LINEAR, 0.33f, scrimUpperBoundFromSplit)
                             : LINEAR);
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATE);
             config.setInterpolator(ANIM_WORKSPACE_FADE, ACCELERATE);
 
-            if (DisplayController.getNavigationMode(mActivity).hasGestures
+            if (DisplayController.getNavigationMode(mContainer).hasGestures
                     && overview.getTaskViewCount() > 0) {
                 // Overview is going offscreen, so keep it at its current scale and opacity.
                 config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
@@ -136,9 +136,9 @@
                 config.duration = Math.max(config.duration, scrollDuration);
 
                 // Sync scroll so that it ends before or at the same time as the taskbar animation.
-                if (DisplayController.isTransientTaskbar(mActivity)
-                        && mActivity.getDeviceProfile().isTaskbarPresent) {
-                    config.duration = Math.min(config.duration, TASKBAR_TO_HOME_DURATION);
+                if (mContainer.getDeviceProfile().isTaskbarPresent) {
+                    config.duration = Math.min(
+                            config.duration, QuickstepTransitionManager.getTaskbarToHomeDuration());
                 }
                 overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
             } else {
@@ -147,7 +147,7 @@
                 config.setInterpolator(ANIM_OVERVIEW_FADE, DECELERATE_1_7);
             }
 
-            Workspace<?> workspace = mActivity.getWorkspace();
+            Workspace<?> workspace = mContainer.getWorkspace();
             // Start from a higher workspace scale, but only if we're invisible so we don't jump.
             boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
             if (isWorkspaceVisible) {
@@ -160,7 +160,7 @@
                 workspace.setScaleX(WORKSPACE_PREPARE_SCALE);
                 workspace.setScaleY(WORKSPACE_PREPARE_SCALE);
             }
-            Hotseat hotseat = mActivity.getHotseat();
+            Hotseat hotseat = mContainer.getHotseat();
             boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
             if (!isHotseatVisible) {
                 hotseat.setScaleX(WORKSPACE_PREPARE_SCALE);
@@ -168,7 +168,7 @@
             }
         } else if ((fromState == NORMAL || fromState == HINT_STATE
                 || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) {
-            if (DisplayController.getNavigationMode(mActivity).hasGestures) {
+            if (DisplayController.getNavigationMode(mContainer).hasGestures) {
                 config.setInterpolator(ANIM_WORKSPACE_SCALE,
                         fromState == NORMAL ? ACCELERATE : OVERSHOOT_1_2);
                 config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCELERATE);
@@ -201,18 +201,18 @@
         } else if (fromState == HINT_STATE && toState == NORMAL) {
             config.setInterpolator(ANIM_DEPTH, DECELERATE_3);
             if (mHintToNormalDuration == -1) {
-                ValueAnimator va = getWorkspaceSpringScaleAnimator(mActivity,
-                        mActivity.getWorkspace(),
-                        toState.getWorkspaceScaleAndTranslation(mActivity).scale);
+                ValueAnimator va = getWorkspaceSpringScaleAnimator(mContainer,
+                        mContainer.getWorkspace(),
+                        toState.getWorkspaceScaleAndTranslation(mContainer).scale);
                 mHintToNormalDuration = (int) va.getDuration();
             }
             config.duration = Math.max(config.duration, mHintToNormalDuration);
         } else if (fromState == ALL_APPS && toState == NORMAL) {
-            AllAppsSwipeController.applyAllAppsToNormalConfig(mActivity, config);
+            AllAppsSwipeController.applyAllAppsToNormalConfig(mContainer, config);
         } else if (fromState == NORMAL && toState == ALL_APPS) {
-            AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mActivity, config);
+            AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mContainer, config);
         } else if (fromState == OVERVIEW && toState == OVERVIEW_SPLIT_SELECT) {
-            SplitAnimationTimings timings = mActivity.getDeviceProfile().isTablet
+            SplitAnimationTimings timings = mContainer.getDeviceProfile().isTablet
                     ? SplitAnimationTimings.TABLET_OVERVIEW_TO_SPLIT
                     : SplitAnimationTimings.PHONE_OVERVIEW_TO_SPLIT;
             config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 82a9c05..3ed2d0b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -19,7 +19,7 @@
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
-import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
+import static com.android.launcher3.LauncherAnimUtils.newSingleUseCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
@@ -54,7 +54,7 @@
 import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.quickstep.views.RecentsView;
 
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 
 /**
  * Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
@@ -67,7 +67,7 @@
     private static final float OVERVIEW_TO_HOME_SCRIM_MULTIPLIER = 0.5f;
 
     private final Launcher mLauncher;
-    private final Consumer<AnimatorSet> mCancelSplitRunnable;
+    private final BiConsumer<AnimatorSet, Long> mCancelSplitRunnable;
     private final SingleAxisSwipeDetector mSwipeDetector;
     private final float mPullbackDistance;
 
@@ -81,7 +81,7 @@
      *                            Animation should be added to the provided AnimatorSet
      */
     public NavBarToHomeTouchController(Launcher launcher,
-            Consumer<AnimatorSet> cancelSplitRunnable) {
+            BiConsumer<AnimatorSet, Long> cancelSplitRunnable) {
         mLauncher = launcher;
         mCancelSplitRunnable = cancelSplitRunnable;
         mSwipeDetector = new SingleAxisSwipeDetector(mLauncher, this,
@@ -165,7 +165,7 @@
             topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder);
         }
         mCurrentAnimation = builder.createPlaybackController();
-        mCurrentAnimation.getTarget().addListener(newCancelListener(this::clearState));
+        mCurrentAnimation.getTarget().addListener(newSingleUseCancelListener(this::clearState));
     }
 
     private void clearState() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index ca598c8..42be52f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -18,7 +18,7 @@
 
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
-import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
+import static com.android.launcher3.LauncherAnimUtils.newSingleUseCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -38,6 +38,7 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
@@ -53,8 +54,9 @@
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 
 /**
  * Touch controller which handles swipe and hold from the nav bar to go to Overview. Swiping above
@@ -70,7 +72,7 @@
     private static final float TRANSLATION_ANIM_VELOCITY_DP_PER_MS = 0.8f;
 
     private final VibratorWrapper mVibratorWrapper;
-    private final Consumer<AnimatorSet> mCancelSplitRunnable;
+    private final BiConsumer<AnimatorSet, Long> mCancelSplitRunnable;
     private final RecentsView mRecentsView;
     private final MotionPauseDetector mMotionPauseDetector;
     private final float mMotionPauseMinDisplacement;
@@ -91,7 +93,7 @@
      *                            Animation should be added to the provided AnimatorSet
      */
     public NoButtonNavbarToOverviewTouchController(Launcher l,
-            Consumer<AnimatorSet> cancelSplitRunnable) {
+            BiConsumer<AnimatorSet, Long> cancelSplitRunnable) {
         super(l);
         mRecentsView = l.getOverviewPanel();
         mMotionPauseDetector = new MotionPauseDetector(l);
@@ -148,6 +150,8 @@
         mMotionPauseDetector.clear();
 
         if (handlingOverviewAnim()) {
+            InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+                    "Home");
             mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
         }
 
@@ -182,6 +186,7 @@
         if (mStartedOverview) {
             goToOverviewOrHomeOnDragEnd(velocity);
         } else {
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
             super.onDragEnd(velocity);
         }
 
@@ -203,9 +208,10 @@
             // Normally we compute the duration based on the velocity and distance to the given
             // state, but since the hint state tracks the entire screen without a clear endpoint, we
             // need to manually set the duration to a reasonable value.
-            animator.setDuration(HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */));
+            long duration = HINT_STATE.getTransitionDuration(mLauncher, true /* isToState */);
+            animator.setDuration(duration);
             AnimatorSet animatorSet = new AnimatorSet();
-            mCancelSplitRunnable.accept(animatorSet);
+            mCancelSplitRunnable.accept(animatorSet, duration);
             animatorSet.start();
         }
         if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() &&
@@ -220,7 +226,7 @@
             return;
         }
         mNormalToHintOverviewScrimAnimator = null;
-        mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
+        mCurrentAnimation.getTarget().addListener(newSingleUseCancelListener(() ->
                 mLauncher.getStateManager().goToState(OVERVIEW, true, forSuccessCallback(() -> {
                     mOverviewResistYAnim = AnimatorControllerWithResistance
                             .createRecentsResistanceFromOverviewAnim(mLauncher, null)
@@ -237,6 +243,7 @@
 
     private void maybeSwipeInteractionToOverviewComplete() {
         if (mReachedOverview && !mDetector.isDraggingState()) {
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
             onSwipeInteractionCompleted(OVERVIEW);
         }
     }
@@ -280,6 +287,7 @@
         if (goToHomeInsteadOfOverview) {
             new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL), null)
                     .animateWithVelocity(velocity);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         }
         if (mReachedOverview) {
             float distanceDp = dpiFromPx(Math.max(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 968faf0..527a776 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.uioverrides.touchcontrollers;
 
 import static android.view.MotionEvent.ACTION_DOWN;
+
 import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
 import static com.android.app.animation.Interpolators.DECELERATE_3;
 import static com.android.app.animation.Interpolators.LINEAR;
@@ -48,7 +49,6 @@
 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -65,6 +65,7 @@
 import android.view.MotionEvent;
 import android.view.animation.Interpolator;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -83,7 +84,6 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.WorkspaceRevealAnim;
-import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
@@ -107,9 +107,9 @@
     private final float mMaxYProgress;
     private final MotionPauseDetector mMotionPauseDetector;
     private final float mMotionPauseMinDisplacement;
-    private final LauncherRecentsView mRecentsView;
+    private final RecentsView mRecentsView;
     protected final AnimatorListener mClearStateOnCancelListener =
-            newCancelListener(this::clearState);
+            newCancelListener(this::clearState, /* isSingleUse = */ false);
 
     private boolean mNoIntercept;
     private LauncherState mStartState;
@@ -176,10 +176,6 @@
         if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
             return false;
         }
-        if (isDesktopModeSupported()) {
-            // TODO(b/268075592): add support for quickswitch to/from desktop
-            return false;
-        }
         if (isTrackpadMultiFingerSwipe(ev)) {
             return isTrackpadFourFingerSwipe(ev);
         }
@@ -190,8 +186,9 @@
     public void onDragStart(boolean start) {
         mMotionPauseDetector.clear();
         if (start) {
-            InteractionJankMonitorWrapper.begin(mRecentsView,
-                    InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+                    "Home");
 
             mStartState = mLauncher.getStateManager().getState();
 
@@ -326,8 +323,7 @@
         boolean noFling = !horizontalFling && !verticalFling;
         if (mMotionPauseDetector.isPaused() && noFling) {
             // Going to Overview.
-            cancelAnimations();
-            InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
 
             StateAnimationConfig config = new StateAnimationConfig();
             config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
@@ -349,6 +345,8 @@
                     .dispatchOnStart();
             return;
         }
+        InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
+        cancelAnimations();
 
         final LauncherState targetState;
         if (horizontalFling && verticalFling) {
@@ -445,13 +443,12 @@
                     RecentsView.SCROLL_VIBRATION_PRIMITIVE_SCALE,
                     RecentsView.SCROLL_VIBRATION_FALLBACK);
         } else {
-            InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
         }
 
         nonOverviewAnim.setDuration(Math.max(xDuration, yDuration));
         mNonOverviewAnim.setEndAction(() -> onAnimationToStateCompleted(targetState));
 
-        cancelAnimations();
         xOverviewAnim.start();
         yOverviewAnim.start();
         nonOverviewAnim.start();
@@ -469,7 +466,9 @@
                                         : LAUNCHER_UNKNOWN_SWIPEDOWN));
 
         if (targetState == QUICK_SWITCH_FROM_HOME) {
-            InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+        } else if (targetState == OVERVIEW) {
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         }
 
         mLauncher.getStateManager().goToState(targetState, false, forEndCallback(this::clearState));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 2c937b0..b5914a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -24,6 +24,7 @@
 import android.view.MotionEvent;
 
 import com.android.app.animation.Interpolators;
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
@@ -105,7 +106,7 @@
     protected StateAnimationConfig getConfigForStates(
             LauncherState fromState, LauncherState toState) {
         final StateAnimationConfig config = new StateAnimationConfig();
-        config.userControlled = true;
+        config.animProps |= StateAnimationConfig.USER_CONTROLLED;
         if (fromState == NORMAL && toState == ALL_APPS) {
             AllAppsSwipeController.applyNormalToAllAppsAnimConfig(mLauncher, config);
         } else if (fromState == ALL_APPS && toState == NORMAL) {
@@ -185,18 +186,15 @@
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 InteractionJankMonitorWrapper.begin(
-                        mLauncher.getRootView(), InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+                        mLauncher.getRootView(), Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS, /*tag=*/ "swipe");
                 InteractionJankMonitorWrapper.begin(
-                        mLauncher.getRootView(),
-                        InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+                        mLauncher.getRootView(), Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE);
                 break;
 
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
-                InteractionJankMonitorWrapper.cancel(
-                        InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
-                InteractionJankMonitorWrapper.cancel(
-                        InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+                InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
+                InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE);
                 break;
         }
         return super.onControllerInterceptTouchEvent(ev);
@@ -207,11 +205,10 @@
     protected void onReinitToState(LauncherState newToState) {
         super.onReinitToState(newToState);
         if (newToState != ALL_APPS) {
-            InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
         }
         if (newToState != NORMAL) {
-            InteractionJankMonitorWrapper.cancel(
-                    InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE);
         }
     }
 
@@ -219,18 +216,16 @@
     protected void onReachedFinalState(LauncherState toState) {
         super.onReachedFinalState(toState);
         if (toState == ALL_APPS) {
-            InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
         } else if (toState == NORMAL) {
-            InteractionJankMonitorWrapper.end(
-                    InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE);
         }
     }
 
     @Override
     protected void clearState() {
         super.clearState();
-        InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
-        InteractionJankMonitorWrapper.cancel(
-                InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+        InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
+        InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_SWIPE);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index ff142fe..05a55d0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -30,7 +30,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
@@ -39,12 +38,12 @@
 
 import android.view.MotionEvent;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.SystemUiProxy;
@@ -59,11 +58,12 @@
 
     protected final RecentsView mOverviewPanel;
 
-    public QuickSwitchTouchController(Launcher launcher) {
+    public QuickSwitchTouchController(QuickstepLauncher launcher) {
         this(launcher, SingleAxisSwipeDetector.HORIZONTAL);
     }
 
-    protected QuickSwitchTouchController(Launcher l, SingleAxisSwipeDetector.Direction dir) {
+    protected QuickSwitchTouchController(QuickstepLauncher l,
+            SingleAxisSwipeDetector.Direction dir) {
         super(l, dir);
         mOverviewPanel = l.getOverviewPanel();
     }
@@ -79,10 +79,6 @@
         if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
             return false;
         }
-        if (isDesktopModeSupported()) {
-            // TODO(b/268075592): add support for quickswitch to/from desktop
-            return false;
-        }
         return true;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index cda7855..d98e608 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -104,7 +104,7 @@
         if (!mCanIntercept) {
             return false;
         }
-        if (action == ACTION_MOVE) {
+        if (action == ACTION_MOVE && mDownEvents.contains(pid)) {
             float dy = ev.getY(idx) - mDownEvents.get(pid).y;
             float dx = ev.getX(idx) - mDownEvents.get(pid).x;
             if (mIsTrackpadReverseScroll) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 19bfe06..300d697 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -21,7 +21,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.os.SystemClock;
+import android.content.Context;
 import android.os.VibrationEffect;
 import android.view.MotionEvent;
 import android.view.View;
@@ -29,28 +29,28 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.BaseSwipeDetector;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.FlingBlockCheck;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.VibrationConstants;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
 
 /**
  * Touch controller for handling task view card swipes
  */
-public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
+public abstract class TaskViewTouchController<CONTAINER extends Context & RecentsViewContainer>
         extends AnimatorListenerAdapter implements TouchController,
         SingleAxisSwipeDetector.Listener {
 
@@ -59,12 +59,12 @@
     private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
 
     public static final int TASK_DISMISS_VIBRATION_PRIMITIVE =
-            Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
+            VibrationEffect.Composition.PRIMITIVE_TICK;
     public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f;
     public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK =
             VibrationConstants.EFFECT_TEXTURE_TICK;
 
-    protected final T mActivity;
+    protected final CONTAINER mContainer;
     private final SingleAxisSwipeDetector mDetector;
     private final RecentsView mRecentsView;
     private final int[] mTempCords = new int[2];
@@ -80,6 +80,7 @@
     private float mDisplacementShift;
     private float mProgressMultiplier;
     private float mEndDisplacement;
+    private boolean mDraggingEnabled = true;
     private FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
     private Float mOverrideVelocity = null;
 
@@ -87,13 +88,13 @@
 
     private boolean mIsDismissHapticRunning = false;
 
-    public TaskViewTouchController(T activity) {
-        mActivity = activity;
-        mRecentsView = activity.getOverviewPanel();
-        mIsRtl = Utilities.isRtl(activity.getResources());
+    public TaskViewTouchController(CONTAINER container) {
+        mContainer = container;
+        mRecentsView = container.getOverviewPanel();
+        mIsRtl = Utilities.isRtl(container.getResources());
         SingleAxisSwipeDetector.Direction dir =
                 mRecentsView.getPagedOrientationHandler().getUpDownSwipeDirection();
-        mDetector = new SingleAxisSwipeDetector(activity, this, dir);
+        mDetector = new SingleAxisSwipeDetector(container, this, dir);
     }
 
     private boolean canInterceptTouch(MotionEvent ev) {
@@ -113,7 +114,7 @@
             return true;
         }
         if (AbstractFloatingView.getTopOpenViewWithType(
-                mActivity, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
+                mContainer, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
             return false;
         }
         return isRecentsInteractive();
@@ -159,7 +160,7 @@
                 for (int i = 0; i < mRecentsView.getTaskViewCount(); i++) {
                     TaskView view = mRecentsView.getTaskViewAt(i);
 
-                    if (mRecentsView.isTaskViewVisible(view) && mActivity.getDragLayer()
+                    if (mRecentsView.isTaskViewVisible(view) && mContainer.getDragLayer()
                             .isEventOverView(view, ev)) {
                         // Disable swiping up and down if the task overlay is modal.
                         if (isRecentsModal()) {
@@ -179,7 +180,7 @@
                         // - It's the focused task if in grid view
                         // - The task is snapped
                         mAllowGoingDown = i == mRecentsView.getCurrentPage()
-                                && DisplayController.getNavigationMode(mActivity).hasGestures
+                                && DisplayController.getNavigationMode(mContainer).hasGestures
                                 && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask())
                                 && mRecentsView.isTaskInExpectedScrollPosition(i);
 
@@ -225,9 +226,10 @@
             mCurrentAnimation.dispatchOnCancel();
         }
 
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         mCurrentAnimationIsGoingUp = goingUp;
-        BaseDragLayer dl = mActivity.getDragLayer();
+        BaseDragLayer dl = mContainer.getDragLayer();
         final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl);
         long maxDuration = 2 * secondaryLayerDimension;
         int verticalFactor = orientationHandler.getTaskDragDisplacementFactor(mIsRtl);
@@ -269,7 +271,10 @@
 
     @Override
     public void onDragStart(boolean start, float startDisplacement) {
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        if (!mDraggingEnabled) return;
+
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         if (mCurrentAnimation == null) {
             reInitAnimationController(orientationHandler.isGoingUp(startDisplacement, mIsRtl));
             mDisplacementShift = 0;
@@ -283,7 +288,10 @@
 
     @Override
     public boolean onDrag(float displacement) {
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        if (!mDraggingEnabled) return true;
+
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         float totalDisplacement = displacement + mDisplacementShift;
         boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
                 orientationHandler.isGoingUp(totalDisplacement, mIsRtl);
@@ -314,12 +322,9 @@
                 mOverrideVelocity = -mTaskBeingDragged.getResources().getDimension(velocityDimenId);
 
                 // Once halfway through task dismissal interpolation, switch from reversible
-                // dragging-task animation to playing the remaining task translation animations
-                final long now = SystemClock.uptimeMillis();
-                MotionEvent upAction = MotionEvent.obtain(now, now,
-                        MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
-                mDetector.onTouchEvent(upAction);
-                upAction.recycle();
+                // dragging-task animation to playing the remaining task translation animations,
+                // while this is in progress disable dragging.
+                mDraggingEnabled = false;
             }
         } else {
             mCurrentAnimation.setPlayFraction(
@@ -340,13 +345,14 @@
                 R.dimen.max_task_dismiss_drag_velocity);
         velocity = Utilities.boundToRange(velocity, -maxTaskDismissDragVelocity,
                 maxTaskDismissDragVelocity);
-        boolean fling = mDetector.isFling(velocity);
+        boolean fling = mDraggingEnabled && mDetector.isFling(velocity);
         final boolean goingToEnd;
         boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
         if (blockedFling) {
             fling = false;
         }
-        PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                mRecentsView.getPagedOrientationHandler();
         boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
         float progress = mCurrentAnimation.getProgressFraction();
         float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
@@ -367,19 +373,21 @@
                 MIN_TASK_DISMISS_ANIMATION_DURATION, MAX_TASK_DISMISS_ANIMATION_DURATION);
 
         mCurrentAnimation.setEndAction(this::clearState);
-        mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
-                velocity * orientationHandler.getSecondaryTranslationDirectionFactor(),
+        mCurrentAnimation.startWithVelocity(mContainer, goingToEnd, Math.abs(velocity),
                 mEndDisplacement, animationDuration);
         if (goingUp && goingToEnd && !mIsDismissHapticRunning) {
-            VibratorWrapper.INSTANCE.get(mActivity).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE,
+            VibratorWrapper.INSTANCE.get(mContainer).vibrate(TASK_DISMISS_VIBRATION_PRIMITIVE,
                     TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE, TASK_DISMISS_VIBRATION_FALLBACK);
             mIsDismissHapticRunning = true;
         }
+
+        mDraggingEnabled = true;
     }
 
     private void clearState() {
         mDetector.finishedScrolling();
         mDetector.setDetectableScrollConditions(0, false);
+        mDraggingEnabled = true;
         mTaskBeingDragged = null;
         mCurrentAnimation = null;
         mIsDismissHapticRunning = false;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
index 8f9c014..b70cabe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TransposedQuickSwitchTouchController.java
@@ -15,13 +15,13 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 
 public class TransposedQuickSwitchTouchController extends QuickSwitchTouchController {
 
-    public TransposedQuickSwitchTouchController(Launcher launcher) {
+    public TransposedQuickSwitchTouchController(QuickstepLauncher launcher) {
         super(launcher, SingleAxisSwipeDetector.VERTICAL);
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
index 9f2c1d4..31c9b3e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
@@ -27,10 +27,10 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.AllAppsEduView;
@@ -51,7 +51,7 @@
 
     private int mContinuousTouchCount = 0;
 
-    public TwoButtonNavbarTouchController(Launcher l) {
+    public TwoButtonNavbarTouchController(QuickstepLauncher l) {
         super(l, l.getDeviceProfile().isVerticalBarLayout()
                 ? SingleAxisSwipeDetector.HORIZONTAL : SingleAxisSwipeDetector.VERTICAL);
         mIsTransposed = l.getDeviceProfile().isVerticalBarLayout();
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d7ff59e..8e4dde2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -23,12 +23,14 @@
 
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.app.animation.Interpolators.DECELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.app.animation.Interpolators.OVERSHOOT_1_2;
 import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
 import static com.android.launcher3.BaseActivity.EVENT_STARTED;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.PagedView.INVALID_PAGE;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -56,7 +58,6 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.INVALID_VELOCITY_ON_SWIPE_UP;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
@@ -64,7 +65,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.app.WindowConfiguration;
@@ -75,7 +75,6 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
 import android.os.IBinder;
 import android.os.SystemClock;
 import android.util.Log;
@@ -96,10 +95,10 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.internal.jank.Cuj;
 import com.android.internal.util.LatencyTracker;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
@@ -109,7 +108,6 @@
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.BaseState;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarThresholdUtils;
 import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -135,7 +133,9 @@
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TaskViewSimulator;
+import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
 import com.android.systemui.shared.recents.model.Task;
@@ -160,8 +160,7 @@
 /**
  * Handles the navigation gestures when Launcher is the default home activity.
  */
-@TargetApi(Build.VERSION_CODES.R)
-public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
+public abstract class AbsSwipeUpHandler<T extends RecentsViewContainer,
         Q extends RecentsView, S extends BaseState<S>>
         extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
         RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -169,7 +168,10 @@
 
     private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
 
-    protected final BaseActivityInterface<S, T> mActivityInterface;
+    // Fraction of the scroll and transform animation in which the current task fades out
+    private static final float KQS_TASK_FADE_ANIMATION_FRACTION = 0.4f;
+
+    protected final BaseContainerInterface<S, T> mContainerInterface;
     protected final InputConsumerProxy mInputConsumerProxy;
     protected final ActivityInitListener mActivityInitListener;
     // Callbacks to be made once the recents animation starts
@@ -180,7 +182,7 @@
     protected @Nullable RecentsAnimationController mRecentsAnimationController;
     protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController;
     protected RecentsAnimationTargets mRecentsAnimationTargets;
-    protected @Nullable T mActivity;
+    protected @Nullable T mContainer;
     protected @Nullable Q mRecentsView;
     protected Runnable mGestureEndCallback;
     protected MultiStateCallback mStateCallback;
@@ -190,7 +192,7 @@
     private final Runnable mLauncherOnDestroyCallback = () -> {
         ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
         mRecentsView = null;
-        mActivity = null;
+        mContainer = null;
         mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
     };
 
@@ -345,8 +347,9 @@
             long touchTimeMs, boolean continuingLastGesture,
             InputConsumerController inputConsumer) {
         super(context, deviceState, gestureState);
-        mActivityInterface = gestureState.getActivityInterface();
-        mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
+        mContainerInterface = gestureState.getContainerInterface();
+        mActivityInitListener =
+                mContainerInterface.createActivityInitListener(this::onActivityInit);
         mInputConsumerProxy =
                 new InputConsumerProxy(context, /* rotationSupplier = */ () -> {
                     if (mRecentsView == null) {
@@ -356,7 +359,7 @@
                 }, inputConsumer, /* onTouchDownCallback = */ () -> {
                     endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
                     endLauncherTransitionController();
-                }, new InputProxyHandlerFactory(mActivityInterface, mGestureState));
+                }, new InputProxyHandlerFactory(mContainerInterface, mGestureState));
         mTaskAnimationManager = taskAnimationManager;
         mTouchTimeMs = touchTimeMs;
         mContinuingLastGesture = continuingLastGesture;
@@ -373,8 +376,8 @@
         initStateCallbacks();
 
         mIsTransientTaskbar = mDp.isTaskbarPresent
-                && DisplayController.isTransientTaskbar(mActivity);
-        TaskbarUIController controller = mActivityInterface.getTaskbarController();
+                && DisplayController.isTransientTaskbar(context);
+        TaskbarUIController controller = mContainerInterface.getTaskbarController();
         mTaskbarAlreadyOpen = controller != null && !controller.isTaskbarStashed();
         mIsTaskbarAllAppsOpen = controller != null && controller.isTaskbarAllAppsOpen();
         mTaskbarAppWindowThreshold =
@@ -471,16 +474,16 @@
             return false;
         }
 
-        T createdActivity = mActivityInterface.getCreatedActivity();
-        if (createdActivity != null) {
-            initTransitionEndpoints(createdActivity.getDeviceProfile());
+        T createdContainer = (T) mContainerInterface.getCreatedContainer();
+        if (createdContainer != null) {
+            initTransitionEndpoints(createdContainer.getDeviceProfile());
         }
-        final T activity = mActivityInterface.getCreatedActivity();
-        if (mActivity == activity) {
+        final T container = (T) mContainerInterface.getCreatedContainer();
+        if (mContainer == container) {
             return true;
         }
 
-        if (mActivity != null) {
+        if (mContainer != null) {
             if (mStateCallback.hasStates(STATE_GESTURE_COMPLETED)) {
                 // If the activity has restarted between setting the page scroll settling callback
                 // and actually receiving the callback, just mark the gesture completed
@@ -495,23 +498,23 @@
             mStateCallback.setState(oldState);
         }
         mWasLauncherAlreadyVisible = alreadyOnHome;
-        mActivity = activity;
+        mContainer = container;
         // Override the visibility of the activity until the gesture actually starts and we swipe
         // up, or until we transition home and the home animation is composed
         if (alreadyOnHome) {
-            mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+            mContainer.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
         } else {
-            mActivity.addForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+            mContainer.addForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
         }
 
-        mRecentsView = activity.getOverviewPanel();
+        mRecentsView = container.getOverviewPanel();
         mRecentsView.setOnPageTransitionEndCallback(null);
 
         mStateCallback.setState(STATE_LAUNCHER_PRESENT);
         if (alreadyOnHome) {
             onLauncherStart();
         } else {
-            activity.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
+            container.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
         }
 
         // Set up a entire animation lifecycle callback to notify the current recents view when
@@ -536,8 +539,8 @@
 
         setupRecentsViewUi();
         mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll);
-        mActivity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
-        mActivity.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
+        mContainer.runOnBindToTouchInteractionService(this::onLauncherBindToService);
+        mContainer.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
         return true;
     }
 
@@ -549,8 +552,8 @@
     }
 
     private void onLauncherStart() {
-        final T activity = mActivityInterface.getCreatedActivity();
-        if (activity == null || mActivity != activity) {
+        final T container = (T) mContainerInterface.getCreatedContainer();
+        if (container == null || mContainer != container) {
             return;
         }
         if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
@@ -566,7 +569,7 @@
         // as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
         if (mGestureState.getEndTarget() != HOME) {
             Runnable initAnimFactory = () -> {
-                mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState,
+                mAnimationFactory = mContainerInterface.prepareRecentsUI(mDeviceState,
                         mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
                 maybeUpdateRecentsAttachedState(false /* animate */);
                 if (mGestureState.getEndTarget() != null) {
@@ -583,14 +586,14 @@
                 initAnimFactory.run();
             }
         }
-        AbstractFloatingView.closeAllOpenViewsExcept(activity, mWasLauncherAlreadyVisible,
+        AbstractFloatingView.closeAllOpenViewsExcept(container, mWasLauncherAlreadyVisible,
                 AbstractFloatingView.TYPE_LISTENER);
 
         if (mWasLauncherAlreadyVisible) {
             mStateCallback.setState(STATE_LAUNCHER_DRAWN);
         } else {
             SafeCloseable traceToken = TraceHelper.INSTANCE.beginAsyncSection("WTS-init");
-            View dragLayer = activity.getDragLayer();
+            View dragLayer = container.getDragLayer();
             dragLayer.getViewTreeObserver().addOnDrawListener(new OnDrawListener() {
                 boolean mHandled = false;
 
@@ -604,7 +607,7 @@
                     traceToken.close();
                     dragLayer.post(() ->
                             dragLayer.getViewTreeObserver().removeOnDrawListener(this));
-                    if (activity != mActivity) {
+                    if (container != mContainer) {
                         return;
                     }
 
@@ -613,7 +616,7 @@
             });
         }
 
-        activity.getRootView().setOnApplyWindowInsetsListener(this);
+        container.getRootView().setOnApplyWindowInsetsListener(this);
         mStateCallback.setState(STATE_LAUNCHER_STARTED);
     }
 
@@ -629,21 +632,21 @@
 
         // For the duration of the gesture, in cases where an activity is launched while the
         // activity is not yet resumed, finish the animation to ensure we get resumed
-        mGestureState.getActivityInterface().setOnDeferredActivityLaunchCallback(
+        mGestureState.getContainerInterface().setOnDeferredActivityLaunchCallback(
                 mOnDeferredActivityLaunch);
 
         mGestureState.runOnceAtState(STATE_END_TARGET_SET,
                 () -> {
                     mDeviceState.getRotationTouchHelper()
                             .onEndTargetCalculated(mGestureState.getEndTarget(),
-                                    mActivityInterface);
+                                    mContainerInterface);
                 });
 
         notifyGestureStarted();
     }
 
     private void onDeferredActivityLaunch() {
-        mActivityInterface.switchRunningTaskViewToScreenshot(
+        mContainerInterface.switchRunningTaskViewToScreenshot(
                 null, () -> {
                     mTaskAnimationManager.finishRunningRecentsAnimation(true /* toHome */);
                 });
@@ -704,7 +707,7 @@
             public void onMotionPauseDetected() {
                 mHasMotionEverBeenPaused = true;
                 maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */);
-                Optional.ofNullable(mActivityInterface.getTaskbarController())
+                Optional.ofNullable(mContainerInterface.getTaskbarController())
                         .ifPresent(TaskbarUIController::startTranslationSpring);
                 if (!mIsInAllAppsRegion) {
                     performHapticFeedback();
@@ -810,7 +813,7 @@
      */
     private void setIsInAllAppsRegion(boolean isInAllAppsRegion) {
         if (mIsInAllAppsRegion == isInAllAppsRegion
-                || !mActivityInterface.allowAllAppsFromOverview()) {
+                || !mContainerInterface.allowAllAppsFromOverview()) {
             return;
         }
         mIsInAllAppsRegion = isInAllAppsRegion;
@@ -819,8 +822,9 @@
         VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
         maybeUpdateRecentsAttachedState(true);
 
-        if (mActivity != null) {
-            mActivity.getAppsView().getSearchUiManager().prepareToFocusEditText(mIsInAllAppsRegion);
+        if (mContainer != null) {
+            mContainer.getAppsView().getSearchUiManager()
+                    .prepareToFocusEditText(mIsInAllAppsRegion);
         }
 
         // Draw active task below Launcher so that All Apps can appear over it.
@@ -833,7 +837,7 @@
         if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
             return;
         }
-        initTransitionEndpoints(mActivity.getDeviceProfile());
+        initTransitionEndpoints(mContainer.getDeviceProfile());
         mAnimationFactory.createActivityInterface(mTransitionDragLength);
     }
 
@@ -844,7 +848,7 @@
      */
     private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
         return mGestureState.getEndTarget() != HOME
-                && !mHasEndedLauncherTransition && mActivity != null;
+                && !mHasEndedLauncherTransition && mContainer != null;
     }
 
     @Override
@@ -888,7 +892,7 @@
     @UiThread
     @Override
     public void onCurrentShiftUpdated() {
-        float threshold = LauncherPrefs.get(mContext).get(ALL_APPS_OVERVIEW_THRESHOLD) / 100f;
+        float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
         setIsInAllAppsRegion(mCurrentShift.value >= threshold);
         updateSysUiFlags(mCurrentShift.value);
         applyScrollAndTransform();
@@ -902,7 +906,10 @@
             return;
         }
         mLauncherTransitionController.setProgress(
-                Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor);
+                // Immediately finish the grid transition
+                isKeyboardTaskFocusPending()
+                        ? 1f : Math.max(mCurrentShift.value, getScaleProgressDueToScroll()),
+                mDragLengthFactor);
     }
 
     /**
@@ -925,11 +932,11 @@
             // needs to be canceled
             mRecentsAnimationController.setWillFinishToHome(swipeUpThresholdPassed);
 
-            if (mActivity == null) return;
+            if (mContainer == null) return;
             if (swipeUpThresholdPassed) {
-                mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
+                mContainer.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
             } else {
-                mActivity.getSystemUiController().updateUiState(
+                mContainer.getSystemUiController().updateUiState(
                         UI_STATE_FULLSCREEN_TASK, centermostTaskFlags);
             }
         }
@@ -939,7 +946,7 @@
     public void onRecentsAnimationStart(RecentsAnimationController controller,
             RecentsAnimationTargets targets) {
         super.onRecentsAnimationStart(controller, targets);
-        if (isDesktopModeSupported() && targets.hasDesktopTasks()) {
+        if (targets.hasDesktopTasks()) {
             mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
         } else {
             int untrimmedAppCount = mRemoteTargetHandles.length;
@@ -957,7 +964,7 @@
 
         // Only initialize the device profile, if it has not been initialized before, as in some
         // configurations targets.homeContentInsets may not be correct.
-        if (mActivity == null) {
+        if (mContainer == null) {
             RemoteAnimationTarget primaryTaskTarget = targets.apps[0];
             // orientation state is independent of which remote target handle we use since both
             // should be pointing to the same one. Just choose index 0 for now since that works for
@@ -966,7 +973,7 @@
                     .getOrientationState();
             DeviceProfile dp = orientationState.getLauncherDeviceProfile();
             if (targets.minimizedHomeBounds != null && primaryTaskTarget != null) {
-                Rect overviewStackBounds = mActivityInterface
+                Rect overviewStackBounds = mContainerInterface
                         .getOverviewWindowBounds(targets.minimizedHomeBounds, primaryTaskTarget);
                 dp = dp.getMultiWindowProfile(mContext,
                         new WindowBounds(overviewStackBounds, targets.homeContentInsets));
@@ -994,7 +1001,7 @@
         ActiveGestureLog.INSTANCE.addLog(
                 /* event= */ "cancelRecentsAnimation",
                 /* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
-        mActivityInitListener.unregister();
+        mActivityInitListener.unregister("AbsSwipeUpHandler.onRecentsAnimationCanceled");
         // Cache the recents animation controller so we can defer its cleanup to after having
         // properly cleaned up the screenshot without accidentally using it.
         mDeferredCleanupRecentsAnimationController = mRecentsAnimationController;
@@ -1009,7 +1016,7 @@
 
     @UiThread
     public void onGestureStarted(boolean isLikelyToStartNewTask) {
-        mActivityInterface.closeOverlay();
+        mContainerInterface.closeOverlay();
         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
 
         if (mRecentsView != null) {
@@ -1024,12 +1031,12 @@
                     }
                     mHandled = true;
 
+                    InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH,
+                            2000 /* ms timeout */);
                     InteractionJankMonitorWrapper.begin(mRecentsView,
-                            InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
+                            Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
                     InteractionJankMonitorWrapper.begin(mRecentsView,
-                            InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
-                    InteractionJankMonitorWrapper.begin(mRecentsView,
-                            InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
+                            Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
 
                     rv.post(() -> rv.getViewTreeObserver().removeOnDrawListener(this));
                 }
@@ -1069,11 +1076,11 @@
      */
     @UiThread
     private void notifyGestureStarted() {
-        final T curActivity = mActivity;
+        final T curActivity = mContainer;
         if (curActivity != null) {
             // Once the gesture starts, we can no longer transition home through the button, so
             // reset the force override of the activity visibility
-            mActivity.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
+            mContainer.clearForceInvisibleFlag(STATE_HANDLER_INVISIBILITY_FLAGS);
         }
     }
 
@@ -1142,19 +1149,16 @@
         maybeUpdateRecentsAttachedState(false);
         final GestureEndTarget endTarget = mGestureState.getEndTarget();
         // Wait until the given View (if supplied) draws before resuming the last task.
-        View postResumeLastTask = mActivityInterface.onSettledOnEndTarget(endTarget);
+        View postResumeLastTask = mContainerInterface.onSettledOnEndTarget(endTarget);
 
         if (endTarget != NEW_TASK) {
-            InteractionJankMonitorWrapper.cancel(
-                    InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
         }
         if (endTarget != HOME) {
-            InteractionJankMonitorWrapper.cancel(
-                    InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
         }
         if (endTarget != RECENTS) {
-            InteractionJankMonitorWrapper.cancel(
-                    InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         }
 
         switch (endTarget) {
@@ -1165,13 +1169,11 @@
                 mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT);
                 // Notify the SysUI to use fade-in animation when entering PiP
                 SystemUiProxy.INSTANCE.get(mContext).setPipAnimationTypeToAlpha();
-                if (isDesktopModeSupported()) {
+                DesktopVisibilityController desktopVisibilityController =
+                        mContainerInterface.getDesktopVisibilityController();
+                if (desktopVisibilityController != null) {
                     // Notify the SysUI to stash desktop apps if they are visible
-                    DesktopVisibilityController desktopVisibilityController =
-                            mActivityInterface.getDesktopVisibilityController();
-                    if (desktopVisibilityController != null) {
-                        desktopVisibilityController.onHomeActionTriggered();
-                    }
+                    desktopVisibilityController.onHomeActionTriggered();
                 }
                 break;
             case RECENTS:
@@ -1250,7 +1252,13 @@
             return LAST_TASK;
         }
 
-        if (isDesktopModeSupported() && endTarget == NEW_TASK) {
+        TaskView nextPageTaskView = mRecentsView != null
+                ? mRecentsView.getNextPageTaskView() : null;
+        TaskView currentPageTaskView = mRecentsView != null
+                ? mRecentsView.getCurrentPageTaskView() : null;
+        if (((nextPageTaskView != null && nextPageTaskView.isDesktopTask())
+                || (currentPageTaskView != null && currentPageTaskView.isDesktopTask()))
+                && endTarget == NEW_TASK) {
             // TODO(b/268075592): add support for quickswitch to/from desktop
             return LAST_TASK;
         }
@@ -1353,8 +1361,10 @@
             }
         }
         Interpolator interpolator;
-        S state = mActivityInterface.stateFromGestureEndTarget(endTarget);
-        if (state.displayOverviewTasksAsGrid(mDp)) {
+        S state = mContainerInterface.stateFromGestureEndTarget(endTarget);
+        if (isKeyboardTaskFocusPending()) {
+            interpolator = EMPHASIZED;
+        } else if (state.displayOverviewTasksAsGrid(mDp)) {
             interpolator = ACCELERATE_DECELERATE;
         } else if (endTarget == RECENTS) {
             interpolator = OVERSHOOT_1_2;
@@ -1366,7 +1376,7 @@
             mInputConsumerProxy.enable();
         }
         if (endTarget == HOME) {
-            duration = mActivity != null && mActivity.getDeviceProfile().isTaskbarPresent
+            duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent
                     ? StaggeredWorkspaceAnim.DURATION_TASKBAR_MS
                     : StaggeredWorkspaceAnim.DURATION_MS;
             // Early detach the nav bar once the endTarget is determined as HOME
@@ -1409,9 +1419,11 @@
             mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
             setClampScrollOffset(false);
         };
-        if (mRecentsView != null) {
+        if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
+                && !mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
             ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
                     .SET_ON_PAGE_TRANSITION_END_CALLBACK);
+            // TODO(b/268075592): add support for quickswitch to/from desktop
             mRecentsView.setOnPageTransitionEndCallback(onPageTransitionEnd);
         } else {
             onPageTransitionEnd.run();
@@ -1501,14 +1513,14 @@
         if (mGestureState.getEndTarget().isLauncher) {
             // This is also called when the launcher is resumed, in order to clear the pending
             // widgets that have yet to be configured.
-            if (mActivity != null) {
-                DragView.removeAllViews(mActivity);
+            if (mContainer != null) {
+                DragView.removeAllViews(mContainer);
             }
 
             TaskStackChangeListeners.getInstance().registerTaskStackListener(
                     mActivityRestartListener);
 
-            mParallelRunningAnim = mActivityInterface.getParallelAnimationToLauncher(
+            mParallelRunningAnim = mContainerInterface.getParallelAnimationToLauncher(
                     mGestureState.getEndTarget(), duration,
                     mTaskAnimationManager.getCurrentCallbacks());
             if (mParallelRunningAnim != null) {
@@ -1574,7 +1586,8 @@
                         mSwipePipToHomeAnimator.getTaskId(),
                         mSwipePipToHomeAnimator.getComponentName(),
                         mSwipePipToHomeAnimator.getDestinationBounds(),
-                        mSwipePipToHomeAnimator.getContentOverlay());
+                        mSwipePipToHomeAnimator.getContentOverlay(),
+                        mSwipePipToHomeAnimator.getAppBounds());
 
                 windowAnim = mSwipePipToHomeAnimators;
             } else {
@@ -1605,7 +1618,7 @@
                 if (windowAnimation == null) {
                     continue;
                 }
-                DeviceProfile dp = mActivity == null ? null : mActivity.getDeviceProfile();
+                DeviceProfile dp = mContainer == null ? null : mContainer.getDeviceProfile();
                 windowAnimation.start(mContext, dp, velocityPxPerMs);
                 mRunningWindowAnim[i] = RunningWindowAnim.wrap(windowAnimation);
             }
@@ -1657,7 +1670,8 @@
             animatorSet.play(windowAnim);
             if (mRecentsView != null) {
                 mRecentsView.onPrepareGestureEndAnimation(
-                        animatorSet, mGestureState.getEndTarget(),
+                        mGestureState.isHandlingAtomicEvent() ? null : animatorSet,
+                        mGestureState.getEndTarget(),
                         getRemoteTaskViewSimulators());
             }
             animatorSet.setDuration(duration).setInterpolator(interpolator);
@@ -1857,7 +1871,7 @@
                 }
                 // Make sure recents is in its final state
                 maybeUpdateRecentsAttachedState(false);
-                mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
+                mContainerInterface.onSwipeUpToHomeComplete(mDeviceState);
             }
         });
         if (mRecentsAnimationTargets != null) {
@@ -1931,8 +1945,8 @@
 
     private void reset() {
         mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
-        if (mActivity != null) {
-            mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
+        if (mContainer != null) {
+            mContainer.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
         }
     }
 
@@ -1949,14 +1963,14 @@
 
         // Cleanup when switching handlers
         mInputConsumerProxy.unregisterOnTouchDownCallback();
-        mActivityInitListener.unregister();
+        mActivityInitListener.unregister("AbsSwipeUpHandler.cancelCurrentAnimation");
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
                 mActivityRestartListener);
         mTaskSnapshotCache.clear();
     }
 
     private void invalidateHandler() {
-        if (!mActivityInterface.isInLiveTileMode() || mGestureState.getEndTarget() != RECENTS) {
+        if (!mContainerInterface.isInLiveTileMode() || mGestureState.getEndTarget() != RECENTS) {
             mInputConsumerProxy.destroy();
             mTaskAnimationManager.setLiveTileCleanUpHandler(null);
         }
@@ -1967,7 +1981,7 @@
             mGestureEndCallback.run();
         }
 
-        mActivityInitListener.unregister();
+        mActivityInitListener.unregister("AbsSwipeUpHandler.invalidateHandler");
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
                 mActivityRestartListener);
         mTaskSnapshotCache.clear();
@@ -2003,11 +2017,11 @@
      * continued quick switch gesture, which cancels the previous handler but doesn't invalidate it.
      */
     private void resetLauncherListeners() {
-        if (mActivity != null) {
-            mActivity.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
-            mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
+        if (mContainer != null) {
+            mContainer.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
+            mContainer.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
 
-            mActivity.getRootView().setOnApplyWindowInsetsListener(null);
+            mContainer.getRootView().setOnApplyWindowInsetsListener(null);
         }
         if (mRecentsView != null) {
             mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener);
@@ -2016,11 +2030,11 @@
 
     private void resetStateForAnimationCancel() {
         boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
-        mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
+        mContainerInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
 
         // Leave the pending invisible flag, as it may be used by wallpaper open animation.
-        if (mActivity != null) {
-            mActivity.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
+        if (mContainer != null) {
+            mContainer.clearForceInvisibleFlag(INVISIBLE_BY_STATE_HANDLER);
         }
     }
 
@@ -2223,12 +2237,29 @@
                     mRecentsAnimationController, mRecentsAnimationTargets);
         });
 
+        if ((mRecentsView.getNextPageTaskView() != null
+                && mRecentsView.getNextPageTaskView().isDesktopTask())
+                || (mRecentsView.getCurrentPageTaskView() != null
+                && mRecentsView.getCurrentPageTaskView().isDesktopTask())) {
+            // TODO(b/268075592): add support for quickswitch to/from desktop
+            mRecentsViewScrollLinked = false;
+            return;
+        }
+
         // Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
         if (!mGestureState.isThreeFingerTrackpadGesture()) {
             mRecentsViewScrollLinked = true;
         }
     }
 
+    private boolean shouldLinkRecentsViewScroll() {
+        return mRecentsViewScrollLinked && !isKeyboardTaskFocusPending();
+    }
+
+    private boolean isKeyboardTaskFocusPending() {
+        return mRecentsView != null && mRecentsView.isKeyboardTaskFocusPending();
+    }
+
     private void onRecentsViewScroll() {
         if (moveWindowWithRecentsScroll()) {
             onCurrentShiftUpdated();
@@ -2269,14 +2300,14 @@
                             onRestartPreviouslyAppearedTask();
                         }
                     } else {
-                        mActivityInterface.onLaunchTaskFailed();
+                        mContainerInterface.onLaunchTaskFailed();
                         if (mRecentsAnimationController != null) {
                             mRecentsAnimationController.finish(true /* toRecents */, null);
                         }
                     }
                 }, true /* freezeTaskList */);
             } else {
-                mActivityInterface.onLaunchTaskFailed();
+                mContainerInterface.onLaunchTaskFailed();
                 Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show();
                 if (mRecentsAnimationController != null) {
                     mRecentsAnimationController.finish(true /* toRecents */, null);
@@ -2368,12 +2399,12 @@
             finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
             return;
         }
-        if (mActivity == null) {
+        if (mContainer == null) {
             ActiveGestureLog.INSTANCE.addLog("Activity destroyed");
             finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
             return;
         }
-        animateSplashScreenExit(mActivity, appearedTaskTargets, taskTarget.leash);
+        animateSplashScreenExit(mContainer, appearedTaskTargets, taskTarget.leash);
     }
 
     private void animateSplashScreenExit(
@@ -2454,11 +2485,49 @@
     /**
      * Registers a callback to run when the activity is ready.
      */
-    public void initWhenReady() {
+    public void initWhenReady(String reasonString) {
         // Preload the plan
         RecentsModel.INSTANCE.get(mContext).getTasks(null);
 
-        mActivityInitListener.register();
+        mActivityInitListener.register(reasonString);
+    }
+
+    private boolean shouldFadeOutTargetsForKeyboardQuickSwitch(
+            TransformParams transformParams,
+            TaskViewSimulator taskViewSimulator,
+            float progress) {
+        RemoteAnimationTargets targets = transformParams.getTargetSet();
+        boolean fadeAppTargets = isKeyboardTaskFocusPending()
+                && targets != null
+                && targets.apps != null
+                && targets.apps.length > 0;
+        float fadeProgress = Utilities.mapBoundToRange(
+                progress,
+                /* lowerBound= */ 0f,
+                /* upperBound= */ KQS_TASK_FADE_ANIMATION_FRACTION,
+                /* toMin= */ 0f,
+                /* toMax= */ 1f,
+                LINEAR);
+        if (!fadeAppTargets || Float.compare(fadeProgress, 1f) == 0) {
+            return false;
+        }
+        SurfaceTransaction surfaceTransaction =
+                transformParams.createSurfaceParams(taskViewSimulator);
+        SurfaceControl.Transaction transaction = surfaceTransaction.getTransaction();
+
+        for (RemoteAnimationTarget app : targets.apps) {
+            transaction.setAlpha(app.leash, 1f - fadeProgress);
+            transaction.setPosition(app.leash,
+                    /* x= */ app.startBounds.left
+                            + (mContainer.getDeviceProfile().overviewPageSpacing
+                            * (mRecentsView.isRtl() ? fadeProgress : -fadeProgress)),
+                    /* y= */ 0f);
+            transaction.setScale(app.leash, 1f, 1f);
+            taskViewSimulator.taskPrimaryTranslation.value =
+                    mRecentsView.getScrollOffsetForKeyboardTaskFocus();
+            taskViewSimulator.apply(transformParams, surfaceTransaction);
+        }
+        return true;
     }
 
     /**
@@ -2470,7 +2539,7 @@
         //    swipe-to-icon animation is handled by RectFSpringAnim anim
         boolean notSwipingToHome = mRecentsAnimationTargets != null
                 && mGestureState.getEndTarget() != HOME;
-        boolean setRecentsScroll = mRecentsViewScrollLinked && mRecentsView != null;
+        boolean setRecentsScroll = shouldLinkRecentsViewScroll() && mRecentsView != null;
         float progress = Math.max(mCurrentShift.value, getScaleProgressDueToScroll());
         int scrollOffset = setRecentsScroll ? mRecentsView.getScrollOffset() : 0;
         if (!mStartMovingTasks && (progress > 0 || scrollOffset != 0)) {
@@ -2489,22 +2558,29 @@
                 if (setRecentsScroll) {
                     taskViewSimulator.setScroll(scrollOffset);
                 }
-                taskViewSimulator.apply(remoteHandle.getTransformParams());
+                TransformParams transformParams = remoteHandle.getTransformParams();
+                if (shouldFadeOutTargetsForKeyboardQuickSwitch(
+                        transformParams, taskViewSimulator, progress)) {
+                    continue;
+                }
+                taskViewSimulator.apply(transformParams);
             }
         }
     }
 
     // Scaling of RecentsView during quick switch based on amount of recents scroll
     private float getScaleProgressDueToScroll() {
-        if (mActivity == null || !mActivity.getDeviceProfile().isTablet || mRecentsView == null
-                || !mRecentsViewScrollLinked) {
+        if (mContainer == null || !mContainer.getDeviceProfile().isTablet || mRecentsView == null
+                || !shouldLinkRecentsViewScroll()) {
             return 0;
         }
 
         float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
+        Rect carouselTaskSize = enableGridOnlyOverview()
+                ? mRecentsView.getLastComputedCarouselTaskSize()
+                : mRecentsView.getLastComputedTaskSize();
         int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
-                mRecentsView.getLastComputedTaskSize().width(),
-                mRecentsView.getLastComputedTaskSize().height());
+                carouselTaskSize.width(), carouselTaskSize.height());
         maxScrollOffset += mRecentsView.getPageSpacing();
 
         float maxScaleProgress =
diff --git a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
new file mode 100644
index 0000000..6fd68d5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS
+import android.app.PendingIntent
+import android.app.RemoteAction
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.view.accessibility.AccessibilityManager
+import com.android.launcher3.R
+import java.util.concurrent.Executor
+
+/**
+ * Registers a [RemoteAction] for toggling All Apps if needed.
+ *
+ * We need this action when either [isHomeAndOverviewSame] or [isTaskbarPresent] is `true`. When
+ * home and overview are the same, we can control Launcher's or Taskbar's All Apps tray. If they are
+ * not the same, but Taskbar is present, we can only control Taskbar's tray.
+ */
+class AllAppsActionManager(
+    private val context: Context,
+    private val bgExecutor: Executor,
+    private val createAllAppsPendingIntent: () -> PendingIntent,
+) {
+
+    /** `true` if home and overview are the same Activity. */
+    var isHomeAndOverviewSame = false
+        set(value) {
+            field = value
+            updateSystemAction()
+        }
+
+    /** `true` if Taskbar is enabled. */
+    var isTaskbarPresent = false
+        set(value) {
+            field = value
+            updateSystemAction()
+        }
+
+    /** `true` if the action should be registered. */
+    var isActionRegistered = false
+        private set
+
+    private fun updateSystemAction() {
+        val shouldRegisterAction = isHomeAndOverviewSame || isTaskbarPresent
+        if (isActionRegistered == shouldRegisterAction) return
+        isActionRegistered = shouldRegisterAction
+
+        bgExecutor.execute {
+            val accessibilityManager =
+                context.getSystemService(AccessibilityManager::class.java) ?: return@execute
+            if (shouldRegisterAction) {
+                accessibilityManager.registerSystemAction(
+                    RemoteAction(
+                        Icon.createWithResource(context, R.drawable.ic_apps),
+                        context.getString(R.string.all_apps_label),
+                        context.getString(R.string.all_apps_label),
+                        createAllAppsPendingIntent(),
+                    ),
+                    GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+                )
+            } else {
+                accessibilityManager.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS)
+            }
+        }
+    }
+
+    fun onDestroy() {
+        isActionRegistered = false
+        context
+            .getSystemService(AccessibilityManager::class.java)
+            ?.unregisterSystemAction(
+                GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+            )
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2dd6a29..00cd60b 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -18,14 +18,11 @@
 import static com.android.app.animation.Interpolators.ACCELERATE_2;
 import static com.android.app.animation.Interpolators.INSTANT;
 import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
-import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -34,25 +31,12 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Build;
-import android.view.Gravity;
 import android.view.MotionEvent;
-import android.view.RemoteAnimationTarget;
-import android.view.View;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
-import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statehandlers.DepthController;
@@ -60,29 +44,23 @@
 import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
-import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.util.HashMap;
 import java.util.Optional;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
 
 /**
  * Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
  */
-@TargetApi(Build.VERSION_CODES.P)
 public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
-        ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>> {
-
-    public final boolean rotationSupportedByActivity;
-
+        ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE> & RecentsViewContainer> extends
+        BaseContainerInterface<STATE_TYPE, ACTIVITY_TYPE> {
     private final STATE_TYPE mBackgroundState;
 
     private STATE_TYPE mTargetState;
@@ -103,7 +81,7 @@
      */
     public void onTransitionCancelled(boolean activityVisible,
             @Nullable GestureState.GestureEndTarget endTarget) {
-        ACTIVITY_TYPE activity = getCreatedActivity();
+        ACTIVITY_TYPE activity = getCreatedContainer();
         if (activity == null) {
             return;
         }
@@ -111,67 +89,37 @@
         if (endTarget != null) {
             // We were on our way to this state when we got canceled, end there instead.
             startState = stateFromGestureEndTarget(endTarget);
-            if (isDesktopModeSupported()) {
-                DesktopVisibilityController controller = getDesktopVisibilityController();
-                if (controller != null && controller.areFreeformTasksVisible()
-                        && endTarget == LAST_TASK) {
-                    // When we are cancelling the transition and going back to last task, move to
-                    // rest state instead when desktop tasks are visible.
-                    // If a fullscreen task is visible, launcher goes to normal state when the
-                    // activity is stopped. This does not happen when freeform tasks are visible
-                    // on top of launcher. Force the launcher state to rest state here.
-                    startState = activity.getStateManager().getRestState();
-                    // Do not animate the transition
-                    activityVisible = false;
-                }
+            DesktopVisibilityController controller = getDesktopVisibilityController();
+            if (controller != null && controller.areDesktopTasksVisible()
+                    && endTarget == LAST_TASK) {
+                // When we are cancelling the transition and going back to last task, move to
+                // rest state instead when desktop tasks are visible.
+                // If a fullscreen task is visible, launcher goes to normal state when the
+                // activity is stopped. This does not happen when desktop tasks are visible
+                // on top of launcher. Force the launcher state to rest state here.
+                startState = activity.getStateManager().getRestState();
+                // Do not animate the transition
+                activityVisible = false;
             }
         }
         activity.getStateManager().goToState(startState, activityVisible);
     }
 
-    public abstract int getSwipeUpDestinationAndLength(
-            DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler);
-
-    /** Called when the animation to home has fully settled. */
-    public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {}
-
-    public abstract void onAssistantVisibilityChanged(float visibility);
-
-    public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
-            boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
-
-    public abstract ActivityInitListener createActivityInitListener(
-            Predicate<Boolean> onInitListener);
-
-    /**
-     * Sets a callback to be run when an activity launch happens while launcher is not yet resumed.
-     */
-    public void setOnDeferredActivityLaunchCallback(Runnable r) {}
-
     @Nullable
-    public abstract ACTIVITY_TYPE getCreatedActivity();
+    public abstract ACTIVITY_TYPE getCreatedContainer();
 
     @Nullable
     public DepthController getDepthController() {
         return null;
     }
 
-    @Nullable
-    public DesktopVisibilityController getDesktopVisibilityController() {
-        return null;
-    }
-
-    @Nullable
-    public abstract TaskbarUIController getTaskbarController();
-
     public final boolean isResumed() {
-        ACTIVITY_TYPE activity = getCreatedActivity();
+        ACTIVITY_TYPE activity = getCreatedContainer();
         return activity != null && activity.hasBeenResumed();
     }
 
     public final boolean isStarted() {
-        ACTIVITY_TYPE activity = getCreatedActivity();
+        ACTIVITY_TYPE activity = getCreatedContainer();
         return activity != null && activity.isStarted();
     }
 
@@ -180,15 +128,7 @@
     public abstract <T extends RecentsView> T getVisibleRecentsView();
 
     @UiThread
-    public abstract boolean switchToRecentsIfVisible(Runnable onCompleteCallback);
-
-    public abstract Rect getOverviewWindowBounds(
-            Rect homeBounds, RemoteAnimationTarget target);
-
-    public abstract boolean allowMinimizeSplitScreen();
-
-    /** @return whether to allow going to All Apps from Overview. */
-    public abstract boolean allowAllAppsFromOverview();
+    public abstract boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener);
 
     public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
         TaskbarUIController controller = getTaskbarController();
@@ -199,20 +139,6 @@
     }
 
     /**
-     * @return Whether the gesture in progress should be cancelled.
-     */
-    public boolean shouldCancelCurrentGesture() {
-        return false;
-    }
-
-    public abstract void onExitOverview(RotationTouchHelper deviceState,
-            Runnable exitRunnable);
-
-    public abstract boolean isInLiveTileMode();
-
-    public abstract void onLaunchTaskFailed();
-
-    /**
      * Closes any overlays.
      */
     public void closeOverlay() {
@@ -222,7 +148,7 @@
 
     public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
             Runnable runnable) {
-        ACTIVITY_TYPE activity = getCreatedActivity();
+        ACTIVITY_TYPE activity = getCreatedContainer();
         if (activity == null) {
             return;
         }
@@ -236,217 +162,9 @@
         recentsView.switchToScreenshot(thumbnailDatas, runnable);
     }
 
-    /**
-     * Calculates the taskView size for the provided device configuration.
-     */
-    public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
-            PagedOrientationHandler orientedState) {
-        if (dp.isTablet) {
-            if (Flags.enableGridOnlyOverview()) {
-                calculateGridTaskSize(context, dp, outRect, orientedState);
-            } else {
-                calculateFocusTaskSize(context, dp, outRect);
-            }
-        } else {
-            Resources res = context.getResources();
-            float maxScale = res.getFloat(R.dimen.overview_max_scale);
-            int taskMargin = dp.overviewTaskMarginPx;
-            calculateTaskSizeInternal(
-                    context,
-                    dp,
-                    dp.overviewTaskThumbnailTopMarginPx,
-                    dp.getOverviewActionsClaimedSpace(),
-                    res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
-                    maxScale,
-                    Gravity.CENTER,
-                    outRect);
-        }
-    }
-
-    private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        Resources res = context.getResources();
-        float maxScale = res.getFloat(R.dimen.overview_max_scale);
-        Rect gridRect = new Rect();
-        calculateGridSize(dp, context, gridRect);
-        calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
-    }
-
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
-            int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
-            Rect outRect) {
-        Rect insets = dp.getInsets();
-
-        Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
-        potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
-        potentialTaskRect.inset(
-                minimumHorizontalPadding,
-                claimedSpaceAbove,
-                minimumHorizontalPadding,
-                claimedSpaceBelow);
-
-        calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
-    }
-
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
-            Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
-        PointF taskDimension = getTaskDimension(context, dp);
-
-        float scale = Math.min(
-                potentialTaskRect.width() / taskDimension.x,
-                potentialTaskRect.height() / taskDimension.y);
-        scale = Math.min(scale, maxScale);
-        int outWidth = Math.round(scale * taskDimension.x);
-        int outHeight = Math.round(scale * taskDimension.y);
-
-        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
-    }
-
-    private static PointF getTaskDimension(Context context, DeviceProfile dp) {
-        PointF dimension = new PointF();
-        getTaskDimension(context, dp, dimension);
-        return dimension;
-    }
-
-    /**
-     * Gets the dimension of the task in the current system state.
-     */
-    public static void getTaskDimension(Context context, DeviceProfile dp, PointF out) {
-        out.x = dp.widthPx;
-        out.y = dp.heightPx;
-        if (dp.isTablet && !DisplayController.isTransientTaskbar(context)) {
-            out.y -= dp.taskbarHeight;
-        }
-    }
-
-    /**
-     * Calculates the overview grid size for the provided device configuration.
-     */
-    public final void calculateGridSize(DeviceProfile dp, Context context, Rect outRect) {
-        Rect insets = dp.getInsets();
-        int topMargin = dp.overviewTaskThumbnailTopMarginPx;
-        int bottomMargin = dp.getOverviewActionsClaimedSpace();
-        if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) {
-            topMargin += context.getResources().getDimensionPixelSize(
-                    R.dimen.overview_top_margin_grid_only);
-            bottomMargin += context.getResources().getDimensionPixelSize(
-                    R.dimen.overview_bottom_margin_grid_only);
-        }
-        int sideMargin = dp.overviewGridSideMargin;
-
-        outRect.set(0, 0, dp.widthPx, dp.heightPx);
-        outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin,
-                Math.max(insets.right, sideMargin), Math.max(insets.bottom, bottomMargin));
-    }
-
-    /**
-     * Calculates the overview grid non-focused task size for the provided device configuration.
-     */
-    public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
-            PagedOrientationHandler orientedState) {
-        Resources res = context.getResources();
-        Rect potentialTaskRect = new Rect();
-        if (Flags.enableGridOnlyOverview()) {
-            calculateGridSize(dp, context, potentialTaskRect);
-        } else {
-            calculateFocusTaskSize(context, dp, potentialTaskRect);
-        }
-
-        float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx
-                - dp.overviewRowSpacing) / 2f;
-
-        PointF taskDimension = getTaskDimension(context, dp);
-        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
-        int outWidth = Math.round(scale * taskDimension.x);
-        int outHeight = Math.round(scale * taskDimension.y);
-
-        int gravity = Gravity.TOP;
-        gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
-        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
-    }
-
-    /**
-     * Calculates the task size for the desktop task
-     */
-    public final void calculateDesktopTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        calculateFocusTaskSize(context, dp, outRect);
-    }
-
-    /**
-     * Calculates the modal taskView size for the provided device configuration
-     */
-    public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
-            PagedOrientationHandler orientedState) {
-        calculateTaskSize(context, dp, outRect, orientedState);
-        boolean isGridOnlyOverview = dp.isTablet && Flags.enableGridOnlyOverview();
-        int claimedSpaceBelow = isGridOnlyOverview
-                ? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarHeight
-                : (dp.heightPx - outRect.bottom - dp.getInsets().bottom);
-        int minimumHorizontalPadding = 0;
-        if (!isGridOnlyOverview) {
-            float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
-            minimumHorizontalPadding =
-                    Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2);
-        }
-        calculateTaskSizeInternal(
-                context,
-                dp,
-                dp.overviewTaskMarginPx,
-                claimedSpaceBelow,
-                minimumHorizontalPadding,
-                1f /*maxScale*/,
-                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
-                outRect);
-    }
-
-    /**
-     * Called when the gesture ends and the animation starts towards the given target. Used to add
-     * an optional additional animation with the same duration.
-     */
-    public @Nullable Animator getParallelAnimationToLauncher(
-            GestureState.GestureEndTarget endTarget, long duration,
-            RecentsAnimationCallbacks callbacks) {
-        if (endTarget == RECENTS) {
-            ACTIVITY_TYPE activity = getCreatedActivity();
-            if (activity == null) {
-                return null;
-            }
-            STATE_TYPE state = stateFromGestureEndTarget(endTarget);
-            ScrimView scrimView = activity.getScrimView();
-            ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
-                    getOverviewScrimColorForState(activity, state));
-            anim.setDuration(duration);
-            return anim;
-        }
-        return null;
-    }
-
-    /**
-     * Returns the color of the scrim behind overview when at rest in this state.
-     * Return {@link Color#TRANSPARENT} for no scrim.
-     */
-    protected abstract int getOverviewScrimColorForState(ACTIVITY_TYPE activity, STATE_TYPE state);
-
-    /**
-     * Returns the expected STATE_TYPE from the provided GestureEndTarget.
-     */
-    public abstract STATE_TYPE stateFromGestureEndTarget(GestureState.GestureEndTarget endTarget);
-
-    /**
-     * Called when the animation to the target has finished, but right before updating the state.
-     * @return A View that needs to draw before ending the recents animation to LAST_TASK.
-     * (This is a hack to ensure Taskbar draws its background first to avoid flickering.)
-     */
-    public @Nullable View onSettledOnEndTarget(GestureState.GestureEndTarget endTarget) {
-        TaskbarUIController taskbarUIController = getTaskbarController();
-        if (taskbarUIController != null) {
-            taskbarUIController.setSystemGestureInProgress(false);
-            return taskbarUIController.getRootView();
-        }
-        return null;
-    }
 
     protected void runOnInitBackgroundStateUI(Runnable callback) {
-        ACTIVITY_TYPE activity = getCreatedActivity();
+        ACTIVITY_TYPE activity = getCreatedContainer();
         if (activity != null && activity.getStateManager().getState() == mBackgroundState) {
             callback.run();
             onInitBackgroundStateUI();
@@ -497,7 +215,7 @@
         DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
             mCallback = callback;
 
-            mActivity = getCreatedActivity();
+            mActivity = getCreatedContainer();
             mStartState = mActivity.getStateManager().getState();
         }
 
@@ -522,7 +240,7 @@
             // Since we are changing the start position of the UI, reapply the state, at the end
             controller.setEndAction(() -> mActivity.getStateManager().goToState(
                     controller.getInterpolatedProgress() > 0.5 ? mTargetState : mBackgroundState,
-                    false));
+                    /* animated= */ false));
 
             RecentsView recentsView = mActivity.getOverviewPanel();
             AnimatorControllerWithResistance controllerWithResistance =
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
new file mode 100644
index 0000000..9955183
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.app.animation.Interpolators.INSTANT;
+import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
+import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
+import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.RemoteAnimationTarget;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
+import com.android.launcher3.R;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.taskbar.TaskbarUIController;
+import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.views.ScrimView;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.HashMap;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
+        CONTAINER_TYPE extends RecentsViewContainer> {
+
+    public boolean rotationSupportedByActivity = false;
+
+    @Nullable
+    public abstract CONTAINER_TYPE getCreatedContainer();
+
+    public abstract boolean isInLiveTileMode();
+
+    public abstract void onAssistantVisibilityChanged(float assistantVisibility);
+
+    public abstract boolean allowMinimizeSplitScreen();
+
+    public abstract boolean isResumed();
+
+    public abstract boolean isStarted();
+    public abstract boolean deferStartingActivity(RecentsAnimationDeviceState deviceState,
+            MotionEvent ev);
+
+    /** @return whether to allow going to All Apps from Overview. */
+    public abstract boolean allowAllAppsFromOverview();
+
+    /**
+     * Returns the color of the scrim behind overview when at rest in this state.
+     * Return {@link Color#TRANSPARENT} for no scrim.
+     */
+    protected abstract int getOverviewScrimColorForState(CONTAINER_TYPE container,
+            STATE_TYPE state);
+
+    public abstract int getSwipeUpDestinationAndLength(
+            DeviceProfile dp, Context context, Rect outRect,
+            RecentsPagedOrientationHandler orientationHandler);
+
+    @Nullable
+    public abstract TaskbarUIController getTaskbarController();
+
+    public abstract BaseActivityInterface.AnimationFactory prepareRecentsUI(
+            RecentsAnimationDeviceState deviceState, boolean activityVisible,
+            Consumer<AnimatorControllerWithResistance> callback);
+
+    public abstract ActivityInitListener createActivityInitListener(
+            Predicate<Boolean> onInitListener);
+    /**
+     * Returns the expected STATE_TYPE from the provided GestureEndTarget.
+     */
+    public abstract STATE_TYPE stateFromGestureEndTarget(GestureState.GestureEndTarget endTarget);
+
+    public abstract void switchRunningTaskViewToScreenshot(HashMap<Integer,
+            ThumbnailData> thumbnailDatas, Runnable runnable);
+
+    public abstract void closeOverlay();
+
+    public abstract Rect getOverviewWindowBounds(
+            Rect homeBounds, RemoteAnimationTarget target);
+
+    public abstract void onLaunchTaskFailed();
+
+    public abstract void onExitOverview(RotationTouchHelper deviceState,
+            Runnable exitRunnable);
+
+    /** Called when the animation to home has fully settled. */
+    public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {}
+
+    /**
+     * Sets a callback to be run when an activity launch happens while launcher is not yet resumed.
+     */
+    public void setOnDeferredActivityLaunchCallback(Runnable r) {}
+    /**
+     * @return Whether the gesture in progress should be cancelled.
+     */
+    public boolean shouldCancelCurrentGesture() {
+        return false;
+    }
+
+    @Nullable
+    public DesktopVisibilityController getDesktopVisibilityController() {
+        return null;
+    }
+
+    /**
+     * Called when the gesture ends and the animation starts towards the given target. Used to add
+     * an optional additional animation with the same duration.
+     */
+    public @Nullable Animator getParallelAnimationToLauncher(
+            GestureState.GestureEndTarget endTarget, long duration,
+            RecentsAnimationCallbacks callbacks) {
+        if (endTarget == RECENTS) {
+            CONTAINER_TYPE container = getCreatedContainer();
+            if (container == null) {
+                return null;
+            }
+            RecentsView recentsView = container.getOverviewPanel();
+            STATE_TYPE state = stateFromGestureEndTarget(endTarget);
+            ScrimView scrimView = container.getScrimView();
+            ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
+                    getOverviewScrimColorForState(container, state));
+            anim.setDuration(duration);
+            anim.setInterpolator(recentsView == null || !recentsView.isKeyboardTaskFocusPending()
+                    ? LINEAR : INSTANT);
+            return anim;
+        }
+        return null;
+    }
+
+    /**
+     * Called when the animation to the target has finished, but right before updating the state.
+     * @return A View that needs to draw before ending the recents animation to LAST_TASK.
+     * (This is a hack to ensure Taskbar draws its background first to avoid flickering.)
+     */
+    public @Nullable View onSettledOnEndTarget(GestureState.GestureEndTarget endTarget) {
+        TaskbarUIController taskbarUIController = getTaskbarController();
+        if (taskbarUIController != null) {
+            taskbarUIController.setSystemGestureInProgress(false);
+            return taskbarUIController.getRootView();
+        }
+        return null;
+    }
+
+    /**
+     * Called when the current gesture transition is cancelled.
+     * @param activityVisible Whether the user can see the changes we make here, so try to animate.
+     * @param endTarget If the gesture ended before we got cancelled, where we were headed.
+     */
+    public void onTransitionCancelled(boolean activityVisible,
+            @Nullable GestureState.GestureEndTarget endTarget) {
+        RecentsViewContainer container = getCreatedContainer();
+        if (container == null) {
+            return;
+        }
+        RecentsView recentsView = container.getOverviewPanel();
+        BaseState startState = recentsView.getStateManager().getRestState();
+        if (endTarget != null) {
+            // We were on our way to this state when we got canceled, end there instead.
+            startState = stateFromGestureEndTarget(endTarget);
+            DesktopVisibilityController controller = getDesktopVisibilityController();
+            if (controller != null && controller.areDesktopTasksVisible()
+                    && endTarget == LAST_TASK) {
+                // When we are cancelling the transition and going back to last task, move to
+                // rest state instead when desktop tasks are visible.
+                // If a fullscreen task is visible, launcher goes to normal state when the
+                // activity is stopped. This does not happen when desktop tasks are visible
+                // on top of launcher. Force the launcher state to rest state here.
+                startState = recentsView.getStateManager().getRestState();
+                // Do not animate the transition
+                activityVisible = false;
+            }
+        }
+        recentsView.getStateManager().goToState(startState, activityVisible);
+    }
+
+    public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        if (dp.isTablet) {
+            if (Flags.enableGridOnlyOverview()) {
+                calculateGridTaskSize(context, dp, outRect, orientedState);
+            } else {
+                calculateFocusTaskSize(context, dp, outRect);
+            }
+        } else {
+            Resources res = context.getResources();
+            float maxScale = res.getFloat(R.dimen.overview_max_scale);
+            int taskMargin = dp.overviewTaskMarginPx;
+            calculateTaskSizeInternal(
+                    context,
+                    dp,
+                    dp.overviewTaskThumbnailTopMarginPx,
+                    dp.getOverviewActionsClaimedSpace(),
+                    res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
+                    maxScale,
+                    Gravity.CENTER,
+                    outRect);
+        }
+    }
+
+    /**
+     * Calculates the taskView size for carousel during app to overview animation on tablets.
+     */
+    public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        if (dp.isTablet && dp.isGestureMode) {
+            Resources res = context.getResources();
+            float minScale = res.getFloat(R.dimen.overview_carousel_min_scale);
+            Rect gridRect = new Rect();
+            calculateGridSize(dp, context, gridRect);
+            calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP,
+                    outRect);
+        } else {
+            calculateTaskSize(context, dp, outRect, orientedState);
+        }
+    }
+
+    private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+        Resources res = context.getResources();
+        float maxScale = res.getFloat(R.dimen.overview_max_scale);
+        Rect gridRect = new Rect();
+        calculateGridSize(dp, context, gridRect);
+        calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
+    }
+
+    private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
+            int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
+            Rect outRect) {
+        Rect insets = dp.getInsets();
+
+        Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
+        potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
+        potentialTaskRect.inset(
+                minimumHorizontalPadding,
+                claimedSpaceAbove,
+                minimumHorizontalPadding,
+                claimedSpaceBelow);
+
+        calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
+    }
+
+    private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
+            Rect potentialTaskRect, float targetScale, int gravity, Rect outRect) {
+        PointF taskDimension = getTaskDimension(context, dp);
+
+        float scale = Math.min(
+                potentialTaskRect.width() / taskDimension.x,
+                potentialTaskRect.height() / taskDimension.y);
+        scale = Math.min(scale, targetScale);
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
+
+        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
+    }
+
+    private static PointF getTaskDimension(Context context, DeviceProfile dp) {
+        PointF dimension = new PointF();
+        getTaskDimension(context, dp, dimension);
+        return dimension;
+    }
+
+    /**
+     * Gets the dimension of the task in the current system state.
+     */
+    public static void getTaskDimension(Context context, DeviceProfile dp, PointF out) {
+        out.x = dp.widthPx;
+        out.y = dp.heightPx;
+        if (dp.isTablet && !DisplayController.isTransientTaskbar(context)) {
+            out.y -= dp.taskbarHeight;
+        }
+    }
+
+    /**
+     * Calculates the overview grid size for the provided device configuration.
+     */
+    public final void calculateGridSize(DeviceProfile dp, Context context, Rect outRect) {
+        Rect insets = dp.getInsets();
+        int topMargin = dp.overviewTaskThumbnailTopMarginPx;
+        int bottomMargin = dp.getOverviewActionsClaimedSpace();
+        if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) {
+            topMargin += context.getResources().getDimensionPixelSize(
+                    R.dimen.overview_top_margin_grid_only);
+            bottomMargin += context.getResources().getDimensionPixelSize(
+                    R.dimen.overview_bottom_margin_grid_only);
+        }
+        int sideMargin = dp.overviewGridSideMargin;
+
+        outRect.set(0, 0, dp.widthPx, dp.heightPx);
+        outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin,
+                Math.max(insets.right, sideMargin), Math.max(insets.bottom, bottomMargin));
+    }
+
+    /**
+     * Calculates the overview grid non-focused task size for the provided device configuration.
+     */
+    public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        Resources res = context.getResources();
+        Rect potentialTaskRect = new Rect();
+        if (Flags.enableGridOnlyOverview()) {
+            calculateGridSize(dp, context, potentialTaskRect);
+        } else {
+            calculateFocusTaskSize(context, dp, potentialTaskRect);
+        }
+
+        float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx
+                - dp.overviewRowSpacing) / 2f;
+
+        PointF taskDimension = getTaskDimension(context, dp);
+        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
+
+        int gravity = Gravity.TOP;
+        gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
+    }
+
+    /**
+     * Calculates the modal taskView size for the provided device configuration
+     */
+    public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        calculateTaskSize(context, dp, outRect, orientedState);
+        boolean isGridOnlyOverview = dp.isTablet && Flags.enableGridOnlyOverview();
+        int claimedSpaceBelow = isGridOnlyOverview
+                ? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarHeight
+                : (dp.heightPx - outRect.bottom - dp.getInsets().bottom);
+        int minimumHorizontalPadding = 0;
+        if (!isGridOnlyOverview) {
+            float maxScale = context.getResources().getFloat(R.dimen.overview_modal_max_scale);
+            minimumHorizontalPadding =
+                    Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2);
+        }
+        calculateTaskSizeInternal(
+                context,
+                dp,
+                dp.overviewTaskMarginPx,
+                claimedSpaceBelow,
+                minimumHorizontalPadding,
+                1f /*maxScale*/,
+                Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
+                outRect);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt b/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
deleted file mode 100644
index 2fc4d04..0000000
--- a/quickstep/src/com/android/quickstep/BootAwarePreloader.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep
-
-import android.content.Context
-import android.util.Log
-import com.android.launcher3.LauncherAppState
-import com.android.launcher3.LauncherPrefs
-import com.android.launcher3.moveStartupDataToDeviceProtectedStorageIsEnabled
-import com.android.launcher3.util.LockedUserState
-
-/**
- * Loads expensive objects in memory before the user is unlocked. This decreases experienced latency
- * when starting the launcher for the first time after a reboot.
- */
-object BootAwarePreloader {
-    private const val TAG = "BootAwarePreloader"
-
-    @JvmStatic
-    fun start(context: Context) {
-        val lp = LauncherPrefs.get(context)
-        when {
-            LockedUserState.get(context).isUserUnlocked ||
-                !moveStartupDataToDeviceProtectedStorageIsEnabled -> {
-                /* No-Op */
-            }
-            lp.isStartupDataMigrated -> {
-                Log.d(TAG, "preloading start up data")
-                LauncherAppState.INSTANCE.get(context)
-            }
-            else -> {
-                Log.d(TAG, "queuing start up data migration to boot aware prefs")
-                LockedUserState.get(context).runOnUserUnlocked {
-                    lp.migrateStartupDataToDeviceProtectedStorage()
-                }
-            }
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/DesktopModeStatus.java b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
new file mode 100644
index 0000000..b1aae16
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
+
+// TODO(b/335401172): Explore unifying logic across core and shell
+public class DesktopModeStatus {
+
+    /**
+     * Flag to indicate whether to restrict desktop mode to supported devices.
+     */
+    private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
+
+    /**
+     * Return {@code true} if desktop mode should be restricted to supported devices.
+     */
+    @VisibleForTesting
+    public static boolean enforceDeviceRestrictions() {
+        return ENFORCE_DEVICE_RESTRICTIONS;
+    }
+
+    /**
+     * Return {@code true} if the current device supports desktop mode.
+     */
+    @VisibleForTesting
+    public static boolean isDesktopModeSupported(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_isDesktopModeSupported);
+    }
+
+    /**
+     * Return {@code true} if desktop mode can be entered on the current device.
+     */
+    public static boolean canEnterDesktopMode(Context context) {
+        return Flags.enableDesktopWindowingMode()
+                && (!enforceDeviceRestrictions() || isDesktopModeSupported(context));
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
new file mode 100644
index 0000000..f26d594
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.view.View
+import com.android.launcher3.AbstractFloatingViewHelper
+import com.android.launcher3.R
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent
+import com.android.launcher3.popup.SystemShortcut
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+
+/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
+class DesktopSystemShortcut(
+    container: RecentsViewContainer,
+    private val mTaskContainer: TaskIdAttributeContainer,
+    abstractFloatingViewHelper: AbstractFloatingViewHelper
+) :
+    SystemShortcut<RecentsViewContainer>(
+        R.drawable.ic_caption_desktop_button_foreground,
+        R.string.recent_task_option_desktop,
+        container,
+        mTaskContainer.itemInfo,
+        mTaskContainer.taskView,
+        abstractFloatingViewHelper
+    ) {
+    override fun onClick(view: View) {
+        dismissTaskMenuView()
+        val recentsView = mTarget!!.getOverviewPanel<RecentsView<*, *>>()
+        recentsView.moveTaskToDesktop(mTaskContainer) {
+            mTarget.statsLogManager
+                .logger()
+                .withItemInfo(mTaskContainer.itemInfo)
+                .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP)
+        }
+    }
+
+    companion object {
+        /** Creates a factory for creating Desktop system shortcuts. */
+        @JvmOverloads
+        fun createFactory(
+            abstractFloatingViewHelper: AbstractFloatingViewHelper = AbstractFloatingViewHelper()
+        ): TaskShortcutFactory {
+            return object : TaskShortcutFactory {
+                override fun getShortcuts(
+                    container: RecentsViewContainer,
+                    taskContainer: TaskIdAttributeContainer
+                ): List<DesktopSystemShortcut>? {
+                    return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
+                    else if (!taskContainer.task.isDockable) null
+                    else
+                        listOf(
+                            DesktopSystemShortcut(
+                                container,
+                                taskContainer,
+                                abstractFloatingViewHelper
+                            )
+                        )
+                }
+
+                override fun showForSplitscreen() = true
+            }
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
new file mode 100644
index 0000000..f68f793
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import com.android.quickstep.util.DeviceConfigHelper
+import com.android.quickstep.util.DeviceConfigHelper.PropReader
+import java.io.PrintWriter
+
+/** Various configurations specific to nav-bar functionalities */
+class DeviceConfigWrapper private constructor(propReader: PropReader) {
+
+    val customLpnhThresholds =
+        propReader.get(
+            "CUSTOM_LPNH_THRESHOLDS",
+            true,
+            "Add dev options and server side control to customize the LPNH trigger slop and milliseconds"
+        )
+
+    val customLphThresholds =
+        propReader.get(
+            "CUSTOM_LPH_THRESHOLDS",
+            true,
+            "Server side control to customize LPH timeout and touch slop"
+        )
+
+    val overrideLpnhLphThresholds =
+        propReader.get(
+            "OVERRIDE_LPNH_LPH_THRESHOLDS",
+            false,
+            "Enable AGSA override for LPNH and LPH timeout and touch slop"
+        )
+
+    val lpnhTimeoutMs =
+        propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds")
+
+    val lpnhSlopPercentage =
+        propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh")
+
+    val enableLpnhTwoStages =
+        propReader.get(
+            "ENABLE_LPNH_TWO_STAGES",
+            false,
+            "Enable two stage for LPNH duration and touch slop"
+        )
+
+    val twoStageMultiplier =
+        propReader.get(
+            "TWO_STAGE_MULTIPLIER",
+            2,
+            "Extends the duration and touch slop if the initial slop is passed"
+        )
+
+    val animateLpnh = propReader.get("ANIMATE_LPNH", false, "Animates navbar when long pressing")
+
+    val shrinkNavHandleOnPress =
+        propReader.get(
+            "SHRINK_NAV_HANDLE_ON_PRESS",
+            false,
+            "Shrinks navbar when long pressing if ANIMATE_LPNH is enabled"
+        )
+
+    val enableLongPressNavHandle =
+        propReader.get(
+            "ENABLE_LONG_PRESS_NAV_HANDLE",
+            true,
+            "Enables long pressing on the bottom bar nav handle to trigger events."
+        )
+
+    val enableSearchHapticHint =
+        propReader.get(
+            "ENABLE_SEARCH_HAPTIC_HINT",
+            true,
+            "Enables haptic hint while long pressing on the bottom bar nav handle."
+        )
+
+    val enableSearchHapticCommit =
+        propReader.get(
+            "ENABLE_SEARCH_HAPTIC_COMMIT",
+            true,
+            "Enables haptic hint at end of long pressing on the bottom bar nav handle."
+        )
+
+    val lpnhHapticHintStartScalePercent =
+        propReader.get("LPNH_HAPTIC_HINT_START_SCALE_PERCENT", 0, "Haptic hint start scale.")
+
+    val lpnhHapticHintEndScalePercent =
+        propReader.get("LPNH_HAPTIC_HINT_END_SCALE_PERCENT", 100, "Haptic hint end scale.")
+
+    val lpnhHapticHintScaleExponent =
+        propReader.get("LPNH_HAPTIC_HINT_SCALE_EXPONENT", 1, "Haptic hint scale exponent.")
+
+    val lpnhHapticHintIterations =
+        propReader.get("LPNH_HAPTIC_HINT_ITERATIONS", 50, "Haptic hint number of iterations.")
+
+    val enableLpnhDeepPress =
+        propReader.get(
+            "ENABLE_LPNH_DEEP_PRESS",
+            true,
+            "Long press of nav handle is instantly triggered if deep press is detected."
+        )
+
+    val lpnhHapticHintDelay =
+        propReader.get("LPNH_HAPTIC_HINT_DELAY", 0, "Delay before haptic hint starts.")
+
+    val lpnhExtraTouchWidthDp =
+        propReader.get(
+            "LPNH_EXTRA_TOUCH_WIDTH_DP",
+            0,
+            "Controls extra dp on the nav bar sides to trigger LPNH. Can be negative for a smaller touch region."
+        )
+
+    val allAppsOverviewThreshold =
+        propReader.get(
+            "ALL_APPS_OVERVIEW_THRESHOLD",
+            180,
+            "Threshold to open All Apps from Overview"
+        )
+
+    /** Dump config values. */
+    fun dump(prefix: String, writer: PrintWriter) {
+        writer.println("$prefix DeviceConfigWrapper:")
+        writer.println("$prefix\tcustomLpnhThresholds=$customLpnhThresholds")
+        writer.println("$prefix\tcustomLphThresholds=$customLphThresholds")
+        writer.println("$prefix\toverrideLpnhLphThresholds=$overrideLpnhLphThresholds")
+        writer.println("$prefix\tlpnhSlopPercentage=$lpnhSlopPercentage")
+        writer.println("$prefix\tanimateLpnh=$animateLpnh")
+        writer.println("$prefix\tshrinkNavHandleOnPress=$shrinkNavHandleOnPress")
+        writer.println("$prefix\tlpnhTimeoutMs=$lpnhTimeoutMs")
+        writer.println("$prefix\tenableLongPressNavHandle=$enableLongPressNavHandle")
+        writer.println("$prefix\tenableSearchHapticHint=$enableSearchHapticHint")
+        writer.println("$prefix\tenableSearchHapticCommit=$enableSearchHapticCommit")
+        writer.println("$prefix\tlpnhHapticHintStartScalePercent=$lpnhHapticHintStartScalePercent")
+        writer.println("$prefix\tlpnhHapticHintEndScalePercent=$lpnhHapticHintEndScalePercent")
+        writer.println("$prefix\tlpnhHapticHintScaleExponent=$lpnhHapticHintScaleExponent")
+        writer.println("$prefix\tlpnhHapticHintIterations=$lpnhHapticHintIterations")
+        writer.println("$prefix\tenableLpnhDeepPress=$enableLpnhDeepPress")
+        writer.println("$prefix\tlpnhHapticHintDelay=$lpnhHapticHintDelay")
+        writer.println("$prefix\tlpnhExtraTouchWidthDp=$lpnhExtraTouchWidthDp")
+        writer.println("$prefix\tallAppsOverviewThreshold=$allAppsOverviewThreshold")
+    }
+
+    companion object {
+        val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
+
+        @JvmStatic fun get() = configHelper.config
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 5c96000..9e896fd 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -32,10 +32,10 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.FallbackTaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.GestureState.GestureEndTarget;
 import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
@@ -60,7 +60,7 @@
     /** 2 */
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
@@ -96,13 +96,13 @@
 
     @Nullable
     @Override
-    public RecentsActivity getCreatedActivity() {
+    public RecentsActivity getCreatedContainer() {
         return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
     }
 
     @Override
     public FallbackTaskbarUIController getTaskbarController() {
-        RecentsActivity activity = getCreatedActivity();
+        RecentsActivity activity = getCreatedContainer();
         if (activity == null) {
             return null;
         }
@@ -112,7 +112,7 @@
     @Nullable
     @Override
     public RecentsView getVisibleRecentsView() {
-        RecentsActivity activity = getCreatedActivity();
+        RecentsActivity activity = getCreatedContainer();
         if (activity != null) {
             if (activity.hasBeenResumed() || isInLiveTileMode()) {
                 return activity.getOverviewPanel();
@@ -122,7 +122,7 @@
     }
 
     @Override
-    public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
+    public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) {
         return false;
     }
 
@@ -154,7 +154,7 @@
 
     @Override
     public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
-        final StateManager<RecentsState> stateManager = getCreatedActivity().getStateManager();
+        final StateManager<RecentsState> stateManager = getCreatedContainer().getStateManager();
         if (stateManager.getState() == HOME) {
             exitRunnable.run();
             notifyRecentsOfOrientation(deviceState);
@@ -177,7 +177,7 @@
 
     @Override
     public boolean isInLiveTileMode() {
-        RecentsActivity activity = getCreatedActivity();
+        RecentsActivity activity = getCreatedContainer();
         return activity != null && activity.getStateManager().getState() == DEFAULT &&
                 activity.isStarted();
     }
@@ -185,7 +185,7 @@
     @Override
     public void onLaunchTaskFailed() {
         // TODO: probably go back to overview instead.
-        RecentsActivity activity = getCreatedActivity();
+        RecentsActivity activity = getCreatedContainer();
         if (activity == null) {
             return;
         }
@@ -209,7 +209,7 @@
 
     private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) {
         // reset layout on swipe to home
-        RecentsView recentsView = getCreatedActivity().getOverviewPanel();
+        RecentsView recentsView = getCreatedContainer().getOverviewPanel();
         recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
                 rotationTouchHelper.getDisplayRotation());
     }
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 57b9a39..92cdf72 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -29,7 +29,6 @@
 import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
 
 import android.animation.ObjectAnimator;
-import android.annotation.TargetApi;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityOptions;
 import android.content.Context;
@@ -37,7 +36,6 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -66,7 +64,6 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.fallback.FallbackRecentsView;
 import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
 import com.android.quickstep.util.TransformParams;
@@ -82,7 +79,6 @@
 /**
  * Handles the navigation gestures when a 3rd party launcher is the default home activity.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class FallbackSwipeHandler extends
         AbsSwipeUpHandler<RecentsActivity, FallbackRecentsView, RecentsState> {
 
@@ -227,7 +223,7 @@
         public AnimatorPlaybackController createActivityAnimationToHome() {
             // copied from {@link LauncherSwipeHandlerV2.LauncherHomeAnimationFactory}
             long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
-            return mActivity.getStateManager().createAnimationToNewWorkspace(
+            return mContainer.getStateManager().createAnimationToNewWorkspace(
                     RecentsState.HOME, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
         }
     }
@@ -375,8 +371,8 @@
                     if (mSpringAnim != null) {
                         mSpringAnim.onTargetPositionChanged();
                     }
-                    mOnFinishCallback = data.getParcelable(EXTRA_ON_FINISH_CALLBACK);
                 }
+                mOnFinishCallback = data.getParcelable(EXTRA_ON_FINISH_CALLBACK);
                 maybeSendEndMessage();
             } catch (Exception e) {
                 // Ignore
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 575be5f..c8a91df 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -29,9 +29,8 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
 
-import android.annotation.TargetApi;
 import android.content.Intent;
-import android.os.Build;
+import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 
@@ -39,10 +38,10 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.statemanager.BaseState;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.io.PrintWriter;
@@ -58,7 +57,6 @@
  * Manages the state for an active system gesture, listens for events from the system and Launcher,
  * and fires events when the states change.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener {
 
     final Predicate<RemoteAnimationTarget> mLastStartedTaskIdPredicate = new Predicate<>() {
@@ -154,7 +152,7 @@
     // Needed to interact with the current activity
     private final Intent mHomeIntent;
     private final Intent mOverviewIntent;
-    private final BaseActivityInterface mActivityInterface;
+    private final BaseContainerInterface mContainerInterface;
     private final MultiStateCallback mStateCallback;
     private final int mGestureId;
 
@@ -185,14 +183,14 @@
     private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots;
 
     /** The time when the swipe up gesture is triggered. */
-    private long mSwipeUpStartTimeMs;
+    private final long mSwipeUpStartTimeMs = SystemClock.uptimeMillis();
 
     private boolean mHandlingAtomicEvent;
 
     public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
         mHomeIntent = componentObserver.getHomeIntent();
         mOverviewIntent = componentObserver.getOverviewIntent();
-        mActivityInterface = componentObserver.getActivityInterface();
+        mContainerInterface = componentObserver.getActivityInterface();
         mStateCallback = new MultiStateCallback(
                 STATE_NAMES.toArray(new String[0]), GestureState::getTrackedEventForState);
         mGestureId = gestureId;
@@ -201,7 +199,7 @@
     public GestureState(GestureState other) {
         mHomeIntent = other.mHomeIntent;
         mOverviewIntent = other.mOverviewIntent;
-        mActivityInterface = other.mActivityInterface;
+        mContainerInterface = other.mContainerInterface;
         mStateCallback = other.mStateCallback;
         mGestureId = other.mGestureId;
         mRunningTask = other.mRunningTask;
@@ -215,7 +213,7 @@
         // Do nothing, only used for initializing the gesture state prior to user unlock
         mHomeIntent = new Intent();
         mOverviewIntent = new Intent();
-        mActivityInterface = null;
+        mContainerInterface = null;
         mStateCallback = new MultiStateCallback(
                 STATE_NAMES.toArray(new String[0]), GestureState::getTrackedEventForState);
         mGestureId = -1;
@@ -271,9 +269,9 @@
     /**
      * @return the interface to the activity handing the UI updates for this gesture.
      */
-    public <S extends BaseState<S>,
-            T extends StatefulActivity<S>> BaseActivityInterface<S, T> getActivityInterface() {
-        return mActivityInterface;
+    public <S extends BaseState<S>, T extends RecentsViewContainer>
+            BaseContainerInterface<S, T> getContainerInterface() {
+        return mContainerInterface;
     }
 
     /**
@@ -511,21 +509,18 @@
         return null;
     }
 
-    void setSwipeUpStartTimeMs(long uptimeMs) {
-        mSwipeUpStartTimeMs = uptimeMs;
-    }
-
     long getSwipeUpStartTimeMs() {
         return mSwipeUpStartTimeMs;
     }
 
-    public void dump(PrintWriter pw) {
-        pw.println("GestureState:");
-        pw.println("  gestureID=" + mGestureId);
-        pw.println("  runningTask=" + mRunningTask);
-        pw.println("  endTarget=" + mEndTarget);
-        pw.println("  lastAppearedTaskTargetId=" + Arrays.toString(mLastAppearedTaskTargets));
-        pw.println("  lastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
-        pw.println("  isRecentsAnimationRunning=" + isRecentsAnimationRunning());
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "GestureState:");
+        pw.println(prefix + "\tgestureID=" + mGestureId);
+        pw.println(prefix + "\trunningTask=" + mRunningTask);
+        pw.println(prefix + "\tendTarget=" + mEndTarget);
+        pw.println(prefix + "\tlastAppearedTaskTargetId="
+                + Arrays.toString(mLastAppearedTaskTargets));
+        pw.println(prefix + "\tlastStartedTaskId=" + Arrays.toString(mLastStartedTaskId));
+        pw.println(prefix + "\tisRecentsAnimationRunning=" + isRecentsAnimationRunning());
     }
 }
diff --git a/quickstep/src/com/android/quickstep/HomeVisibilityState.kt b/quickstep/src/com/android/quickstep/HomeVisibilityState.kt
new file mode 100644
index 0000000..241e16d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/HomeVisibilityState.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.os.RemoteException
+import android.util.Log
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.util.Executors
+import com.android.wm.shell.shared.IHomeTransitionListener.Stub
+import com.android.wm.shell.shared.IShellTransitions
+
+/** Class to track visibility state of Launcher */
+class HomeVisibilityState {
+
+    var isHomeVisible = true
+        private set
+
+    private var listeners = mutableSetOf<VisibilityChangeListener>()
+
+    fun addListener(l: VisibilityChangeListener) = listeners.add(l)
+
+    fun removeListener(l: VisibilityChangeListener) = listeners.remove(l)
+
+    fun init(transitions: IShellTransitions?) {
+        if (!FeatureFlags.enableHomeTransitionListener()) return
+        try {
+            transitions?.setHomeTransitionListener(
+                object : Stub() {
+                    override fun onHomeVisibilityChanged(isVisible: Boolean) {
+                        Executors.MAIN_EXECUTOR.execute {
+                            isHomeVisible = isVisible
+                            listeners.forEach { it.onHomeVisibilityChanged(isVisible) }
+                        }
+                    }
+                }
+            )
+        } catch (e: RemoteException) {
+            Log.w(TAG, "Failed call setHomeTransitionListener", e)
+        }
+    }
+
+    interface VisibilityChangeListener {
+        fun onHomeVisibilityChanged(isVisible: Boolean)
+    }
+
+    override fun toString() = "{HomeVisibilityState isHomeVisible=$isHomeVisible}"
+
+    companion object {
+
+        private const val TAG = "HomeVisibilityState"
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index feaa063..7655c59 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 
@@ -36,7 +35,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherInitListener;
 import com.android.launcher3.LauncherState;
@@ -46,11 +45,11 @@
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.GestureState.GestureEndTarget;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
@@ -74,7 +73,7 @@
 
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout()
                 && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
@@ -86,7 +85,7 @@
 
     @Override
     public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return;
         }
@@ -103,7 +102,7 @@
 
     @Override
     public void onAssistantVisibilityChanged(float visibility) {
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return;
         }
@@ -145,7 +144,7 @@
 
     @Override
     public void setOnDeferredActivityLaunchCallback(Runnable r) {
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return;
         }
@@ -154,14 +153,14 @@
 
     @Nullable
     @Override
-    public QuickstepLauncher getCreatedActivity() {
+    public QuickstepLauncher getCreatedContainer() {
         return QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
     }
 
     @Nullable
     @Override
     public DepthController getDepthController() {
-        QuickstepLauncher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return null;
         }
@@ -171,7 +170,7 @@
     @Nullable
     @Override
     public DesktopVisibilityController getDesktopVisibilityController() {
-        QuickstepLauncher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return null;
         }
@@ -181,7 +180,7 @@
     @Nullable
     @Override
     public LauncherTaskbarUIController getTaskbarController() {
-        QuickstepLauncher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return null;
         }
@@ -191,7 +190,7 @@
     @Nullable
     @Override
     public RecentsView getVisibleRecentsView() {
-        Launcher launcher = getVisibleLauncher();
+        QuickstepLauncher launcher = getVisibleLauncher();
         RecentsView recentsView =
                 launcher != null && launcher.getStateManager().getState().overviewUi
                         ? launcher.getOverviewPanel() : null;
@@ -205,15 +204,24 @@
 
     @Nullable
     @UiThread
-    private Launcher getVisibleLauncher() {
-        Launcher launcher = getCreatedActivity();
-        return (launcher != null) && launcher.isStarted()
-                && (isInLiveTileMode() || launcher.hasBeenResumed()) ? launcher : null;
+    private QuickstepLauncher getVisibleLauncher() {
+        QuickstepLauncher launcher = getCreatedContainer();
+        if (launcher == null) {
+            return null;
+        }
+        if (launcher.isStarted() && (isInLiveTileMode() || launcher.hasBeenResumed())) {
+            return launcher;
+        }
+        if (Flags.useActivityOverlay()
+                && SystemUiProxy.INSTANCE.get(launcher).getHomeVisibilityState().isHomeVisible()) {
+            return launcher;
+        }
+        return null;
     }
 
     @Override
-    public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
-        Launcher launcher = getVisibleLauncher();
+    public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) {
+        QuickstepLauncher launcher = getVisibleLauncher();
         if (launcher == null) {
             return false;
         }
@@ -227,14 +235,14 @@
         closeOverlay();
         launcher.getStateManager().goToState(OVERVIEW,
                 launcher.getStateManager().shouldAnimateStateChange(),
-                onCompleteCallback == null ? null : forEndCallback(onCompleteCallback));
+                animatorListener);
         return true;
     }
 
 
     @Override
     public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
-        final StateManager<LauncherState> stateManager = getCreatedActivity().getStateManager();
+        final StateManager<LauncherState> stateManager = getCreatedContainer().getStateManager();
         stateManager.addStateListener(
                 new StateManager.StateListener<LauncherState>() {
                     @Override
@@ -251,7 +259,7 @@
 
     private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) {
         // reset layout on swipe to home
-        RecentsView recentsView = getCreatedActivity().getOverviewPanel();
+        RecentsView recentsView = getCreatedContainer().getOverviewPanel();
         recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
                 rotationTouchHelper.getDisplayRotation());
     }
@@ -270,12 +278,12 @@
     public boolean allowAllAppsFromOverview() {
         return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()
                 // If floating search bar would not show in overview, don't allow all apps gesture.
-                && OVERVIEW.areElementsVisible(getCreatedActivity(), FLOATING_SEARCH_BAR);
+                && OVERVIEW.areElementsVisible(getCreatedContainer(), FLOATING_SEARCH_BAR);
     }
 
     @Override
     public boolean isInLiveTileMode() {
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
 
         return launcher != null
                 && launcher.getStateManager().getState() == OVERVIEW
@@ -285,7 +293,7 @@
 
     @Override
     public void onLaunchTaskFailed() {
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return;
         }
@@ -295,7 +303,7 @@
     @Override
     public void closeOverlay() {
         super.closeOverlay();
-        Launcher launcher = getCreatedActivity();
+        QuickstepLauncher launcher = getCreatedContainer();
         if (launcher == null) {
             return;
         }
@@ -328,9 +336,8 @@
     }
 
     @Override
-    protected int getOverviewScrimColorForState(QuickstepLauncher launcher,
-            LauncherState state) {
-        return state.getWorkspaceScrimColor(launcher);
+    protected int getOverviewScrimColorForState(QuickstepLauncher activity, LauncherState state) {
+        return state.getWorkspaceScrimColor(activity);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 7c24ba8..79b09fd 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -17,19 +17,20 @@
 package com.android.quickstep;
 
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
 import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
-import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
+import android.content.ComponentCallbacks;
+import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -38,13 +39,12 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Pair;
+import android.view.Choreographer;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.View;
-import android.view.ViewRootImpl;
-import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.window.BackEvent;
@@ -52,14 +52,16 @@
 import android.window.BackProgressAnimator;
 import android.window.IOnBackInvokedCallback;
 
+import com.android.app.animation.Interpolators;
 import com.android.internal.view.AppearanceRegion;
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.systemui.shared.system.QuickStepContract;
 
@@ -82,7 +84,6 @@
  *
  */
 public class LauncherBackAnimationController {
-    private static final int CANCEL_TRANSITION_DURATION = 233;
     private static final int SCRIM_FADE_DURATION = 233;
     private static final float MIN_WINDOW_SCALE = 0.85f;
     private static final float MAX_SCRIM_ALPHA_DARK = 0.8f;
@@ -93,51 +94,50 @@
     private final Matrix mTransformMatrix = new Matrix();
     /** The window position at the beginning of the back animation. */
     private final Rect mStartRect = new Rect();
-    /** The window position when the back gesture is cancelled. */
-    private final RectF mCancelRect = new RectF();
     /** The current window position. */
     private final RectF mCurrentRect = new RectF();
     private final QuickstepLauncher mLauncher;
     private final int mWindowScaleMarginX;
-    /** Max window translation in the Y axis. */
-    private final int mWindowMaxDeltaY;
-    private final float mWindowScaleEndCornerRadius;
-    private final float mWindowScaleStartCornerRadius;
-    private final Interpolator mCancelInterpolator;
-    private final Interpolator mProgressInterpolator = new DecelerateInterpolator();
+    private float mWindowScaleEndCornerRadius;
+    private float mWindowScaleStartCornerRadius;
+    private final Interpolator mProgressInterpolator = Interpolators.BACK_GESTURE;
+    private final Interpolator mVerticalMoveInterpolator = new DecelerateInterpolator();
     private final PointF mInitialTouchPos = new PointF();
 
     private RemoteAnimationTarget mBackTarget;
-    private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+    private RemoteAnimationTarget mLauncherTarget;
+    private View mLauncherTargetView;
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
     private boolean mSpringAnimationInProgress = false;
     private boolean mAnimatorSetInProgress = false;
     private float mBackProgress = 0;
     private boolean mBackInProgress = false;
     private OnBackInvokedCallbackStub mBackCallback;
     private IRemoteAnimationFinishedCallback mAnimationFinishedCallback;
-    private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+    private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
     private SurfaceControl mScrimLayer;
     private ValueAnimator mScrimAlphaAnimator;
     private float mScrimAlpha;
     private boolean mOverridingStatusBarFlags;
 
+    private final ComponentCallbacks mComponentCallbacks = new ComponentCallbacks() {
+        @Override
+        public void onConfigurationChanged(Configuration newConfig) {
+            loadCornerRadius();
+        }
+
+        @Override
+        public void onLowMemory() {}
+    };
+
     public LauncherBackAnimationController(
             QuickstepLauncher launcher,
             QuickstepTransitionManager quickstepTransitionManager) {
         mLauncher = launcher;
         mQuickstepTransitionManager = quickstepTransitionManager;
-        mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
-                mLauncher.getResources())
-                ? mLauncher.getResources().getDimensionPixelSize(
-                        R.dimen.swipe_back_window_corner_radius)
-                : 0;
-        mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+        loadCornerRadius();
         mWindowScaleMarginX = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.swipe_back_window_scale_x_margin);
-        mWindowMaxDeltaY = mLauncher.getResources().getDimensionPixelSize(
-                R.dimen.swipe_back_window_max_delta_y);
-        mCancelInterpolator =
-                AnimationUtils.loadInterpolator(mLauncher, R.interpolator.standard_interpolator);
     }
 
     /**
@@ -175,8 +175,7 @@
             mHandler.post(() -> {
                 LauncherBackAnimationController controller = mControllerRef.get();
                 if (controller != null) {
-                    mProgressAnimator.onBackCancelled(
-                            controller::resetPositionAnimated);
+                    mProgressAnimator.onBackCancelled(controller::onCancelFinished);
                 }
             });
         }
@@ -244,7 +243,9 @@
             for (final RemoteAnimationTarget target : apps) {
                 if (MODE_CLOSING == target.mode) {
                     controller.mBackTarget = target;
-                    break;
+                }
+                if (MODE_OPENING == target.mode) {
+                    controller.mLauncherTarget = target;
                 }
             }
             controller.mAnimationFinishedCallback = finishedCallback;
@@ -254,24 +255,9 @@
         public void onAnimationCancelled() {}
     }
 
-    private void resetPositionAnimated() {
-        ValueAnimator cancelAnimator = ValueAnimator.ofFloat(0, 1);
-        mCancelRect.set(mCurrentRect);
-        cancelAnimator.setDuration(CANCEL_TRANSITION_DURATION);
-        cancelAnimator.setInterpolator(mCancelInterpolator);
-        cancelAnimator.addUpdateListener(
-                animation -> {
-                    updateCancelProgress((float) animation.getAnimatedValue());
-                });
-        cancelAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                // Refresh the status bar appearance to the original one.
-                customizeStatusBarAppearance(false);
-                finishAnimation();
-            }
-        });
-        cancelAnimator.start();
+    private void onCancelFinished() {
+        customizeStatusBarAppearance(false);
+        finishAnimation();
     }
 
     /** Unregisters the back to launcher callback in shell. */
@@ -284,10 +270,18 @@
     }
 
     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: 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;
         RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget();
 
-        if (appTarget == null) {
+        if (appTarget == null || appTarget.leash == null || !appTarget.leash.isValid()) {
             return;
         }
 
@@ -298,21 +292,30 @@
         mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
 
         mStartRect.set(appTarget.windowConfiguration.getMaxBounds());
-        if (mLauncher.getDeviceProfile().isTaskbarPresent && enableTaskbarPinning()
-                && LauncherPrefs.get(mLauncher).get(TASKBAR_PINNING)) {
-            int insetBottom = mStartRect.bottom - appTarget.contentInsets.bottom;
-            mStartRect.set(mStartRect.left, mStartRect.top, mStartRect.right, insetBottom);
-        }
+
+        // inset bottom in case of pinned taskbar being present
+        mStartRect.inset(0, 0, 0, appTarget.contentInsets.bottom);
+
+        mLauncherTargetView = mQuickstepTransitionManager.findLauncherView(
+                new RemoteAnimationTarget[]{ mBackTarget });
+        setLauncherTargetViewVisible(false);
         mCurrentRect.set(mStartRect);
-        addScrimLayer();
-        mTransaction.apply();
+        if (mScrimLayer == null) {
+            addScrimLayer();
+        }
+        applyTransaction();
+    }
+
+    private void setLauncherTargetViewVisible(boolean isVisible) {
+        if (mLauncherTargetView instanceof BubbleTextView) {
+            ((BubbleTextView) mLauncherTargetView).setIconVisible(isVisible);
+        } else if (mLauncherTargetView instanceof LauncherAppWidgetHostView) {
+            mLauncherTargetView.setAlpha(isVisible ? 1f : 0f);
+        }
     }
 
     void addScrimLayer() {
-        ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
-        SurfaceControl parent = viewRootImpl != null
-                ? viewRootImpl.getSurfaceControl()
-                : null;
+        SurfaceControl parent = mLauncherTarget != null ? mLauncherTarget.leash : null;
         if (parent == null || !parent.isValid()) {
             // Parent surface is not ready at the moment. Retry later.
             return;
@@ -340,7 +343,8 @@
             return;
         }
         if (mScrimLayer.isValid()) {
-            mTransaction.remove(mScrimLayer).apply();
+            mTransaction.remove(mScrimLayer);
+            applyTransaction();
         }
         mScrimLayer = null;
     }
@@ -363,7 +367,7 @@
         float yDirection = rawYDelta < 0 ? -1 : 1;
         // limit yDelta interpretation to 1/2 of screen height in either direction
         float deltaYRatio = Math.min(screenHeight / 2f, Math.abs(rawYDelta)) / (screenHeight / 2f);
-        float interpolatedYRatio = mProgressInterpolator.getInterpolation(deltaYRatio);
+        float interpolatedYRatio = mVerticalMoveInterpolator.getInterpolation(deltaYRatio);
         // limit y-shift so surface never passes 8dp screen margin
         float deltaY = yDirection * interpolatedYRatio * Math.max(0f, (screenHeight - height)
                 / 2f - mWindowScaleMarginX);
@@ -382,23 +386,6 @@
         customizeStatusBarAppearance(progress > UPDATE_SYSUI_FLAGS_THRESHOLD);
     }
 
-    private void updateCancelProgress(float progress) {
-        if (mBackTarget == null) {
-            return;
-        }
-        mCurrentRect.set(
-                Utilities.mapRange(progress, mCancelRect.left, mStartRect.left),
-                Utilities.mapRange(progress, mCancelRect.top, mStartRect.top),
-                Utilities.mapRange(progress, mCancelRect.right, mStartRect.right),
-                Utilities.mapRange(progress, mCancelRect.bottom, mStartRect.bottom));
-
-        float endCornerRadius = Utilities.mapRange(
-                mBackProgress, mWindowScaleStartCornerRadius, mWindowScaleEndCornerRadius);
-        float cornerRadius = Utilities.mapRange(
-                progress, endCornerRadius, mWindowScaleStartCornerRadius);
-        applyTransform(mCurrentRect, cornerRadius);
-    }
-
     /** Transform the target window to match the target rect. */
     private void applyTransform(RectF targetRect, float cornerRadius) {
         final float scale = targetRect.width() / mStartRect.width();
@@ -411,7 +398,11 @@
             mTransaction.setWindowCrop(mBackTarget.leash, mStartRect);
             mTransaction.setCornerRadius(mBackTarget.leash, cornerRadius);
         }
+        applyTransaction();
+    }
 
+    private void applyTransaction() {
+        mTransaction.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
         mTransaction.apply();
     }
 
@@ -424,6 +415,7 @@
         if (mLauncher.isDestroyed()) {
             return;
         }
+        mLauncher.setPredictiveBackToHomeInProgress(true);
         LauncherTaskbarUIController taskbarUIController = mLauncher.getTaskbarUIController();
         if (taskbarUIController != null) {
             taskbarUIController.onLauncherVisibilityChanged(true);
@@ -436,6 +428,8 @@
             mLauncher.getStateManager().moveToRestState();
         }
 
+        setLauncherTargetViewVisible(true);
+
         // Explicitly close opened floating views (which is typically called from
         // Launcher#onResumed, but in the predictive back flow launcher is not resumed until
         // the transition is fully finished.)
@@ -456,19 +450,23 @@
                     mBackInProgress /* fromPredictiveBack */);
         startTransitionAnimations(pair.first, pair.second);
         mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
+        customizeStatusBarAppearance(true);
     }
 
     private void finishAnimation() {
+        mLauncher.setPredictiveBackToHomeInProgress(false);
         mBackTarget = null;
+        mLauncherTarget = null;
         mBackInProgress = false;
         mBackProgress = 0;
         mTransformMatrix.reset();
-        mCancelRect.setEmpty();
         mCurrentRect.setEmpty();
         mStartRect.setEmpty();
         mInitialTouchPos.set(0, 0);
         mAnimatorSetInProgress = false;
         mSpringAnimationInProgress = false;
+        setLauncherTargetViewVisible(true);
+        mLauncherTargetView = null;
         // We don't call customizeStatusBarAppearance here to prevent the status bar update with
         // the legacy appearance. It should be refreshed after the transition done.
         mOverridingStatusBarFlags = false;
@@ -519,7 +517,7 @@
             float value = (Float) animation.getAnimatedValue();
             if (mScrimLayer != null && mScrimLayer.isValid()) {
                 mTransaction.setAlpha(mScrimLayer, value * mScrimAlpha);
-                mTransaction.apply();
+                applyTransaction();
             }
         });
         mScrimAlphaAnimator.addListener(new AnimatorListenerAdapter() {
@@ -532,6 +530,30 @@
         anim.start();
     }
 
+    private void loadCornerRadius() {
+        mWindowScaleEndCornerRadius = QuickStepContract.supportsRoundedCornersOnWindows(
+                mLauncher.getResources())
+                ? mLauncher.getResources().getDimensionPixelSize(
+                R.dimen.swipe_back_window_corner_radius)
+                : 0;
+        mWindowScaleStartCornerRadius = QuickStepContract.getWindowCornerRadius(mLauncher);
+    }
+
+    /**
+     * Called when launcher is destroyed. Unregisters component callbacks to avoid memory leaks.
+     */
+    public void unregisterComponentCallbacks() {
+        mLauncher.unregisterComponentCallbacks(mComponentCallbacks);
+    }
+
+    /**
+     * Registers component callbacks with the launcher to receive configuration change events.
+     */
+    public void registerComponentCallbacks() {
+        mLauncher.registerComponentCallbacks(mComponentCallbacks);
+    }
+
+
     private void resetScrim() {
         removeScrimLayer();
         mScrimAlpha = 0;
diff --git a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
index 645ecf4..27bd03d 100644
--- a/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
+++ b/quickstep/src/com/android/quickstep/LauncherRestoreEventLoggerImpl.kt
@@ -5,7 +5,7 @@
 import android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType
 import android.app.backup.BackupRestoreEventLogger.BackupRestoreError
 import android.content.Context
-import com.android.launcher3.Flags
+import com.android.launcher3.Flags.enableLauncherBrMetricsFixed
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger
 
@@ -29,8 +29,8 @@
         @BackupRestoreDataType private const val DATA_TYPE_APP_PAIR = "app_pair"
     }
 
-    private val backupManager: BackupManager = BackupManager(context)
-    private val restoreEventLogger: BackupRestoreEventLogger = backupManager.delayedRestoreLogger
+    private val restoreEventLogger: BackupRestoreEventLogger =
+        BackupManager(context).delayedRestoreLogger
 
     /**
      * For logging when multiple items of a given data type failed to restore.
@@ -44,7 +44,7 @@
         count: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetricsFixed()) {
             restoreEventLogger.logItemsRestoreFailed(dataType, count, error)
         }
     }
@@ -56,7 +56,7 @@
      * @param count the number of data items restored.
      */
     override fun logLauncherItemsRestored(@BackupRestoreDataType dataType: String, count: Int) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetricsFixed()) {
             restoreEventLogger.logItemsRestored(dataType, count)
         }
     }
@@ -67,12 +67,24 @@
      * @param favoritesId The id of the item type from [Favorites] that was restored.
      */
     override fun logSingleFavoritesItemRestored(favoritesId: Int) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetricsFixed()) {
             restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), 1)
         }
     }
 
     /**
+     * Helper to log successfully restoring multiple items from the Favorites table.
+     *
+     * @param favoritesId The id of the item type from [Favorites] that was restored.
+     * @param count number of items that restored.
+     */
+    override fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
+        if (enableLauncherBrMetricsFixed()) {
+            restoreEventLogger.logItemsRestored(favoritesIdToDataType(favoritesId), count)
+        }
+    }
+
+    /**
      * Helper to log a failure to restore a single item from the Favorites table.
      *
      * @param favoritesId The id of the item type from [Favorites] that was not restored.
@@ -82,7 +94,7 @@
         favoritesId: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetricsFixed()) {
             restoreEventLogger.logItemsRestoreFailed(favoritesIdToDataType(favoritesId), 1, error)
         }
     }
@@ -99,7 +111,7 @@
         count: Int,
         @BackupRestoreError error: String?
     ) {
-        if (Flags.enableLauncherBrMetrics()) {
+        if (enableLauncherBrMetricsFixed()) {
             restoreEventLogger.logItemsRestoreFailed(
                 favoritesIdToDataType(favoritesId),
                 count,
@@ -113,8 +125,8 @@
      * done restoring items for Launcher.
      */
     override fun reportLauncherRestoreResults() {
-        if (Flags.enableLauncherBrMetrics()) {
-            backupManager.reportDelayedRestoreResult(restoreEventLogger)
+        if (enableLauncherBrMetricsFixed()) {
+            BackupManager(context).reportDelayedRestoreResult(restoreEventLogger)
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index a9d8afc..af02ccf 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -17,6 +17,7 @@
 
 import static com.android.app.animation.Interpolators.EXAGGERATED_EASE;
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.Utilities.mapBoundToRange;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
@@ -46,6 +47,7 @@
 import com.android.launcher3.views.FloatingView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.views.FloatingWidgetView;
@@ -73,7 +75,7 @@
     protected HomeAnimationFactory createHomeAnimationFactory(ArrayList<IBinder> launchCookies,
             long duration, boolean isTargetTranslucent, boolean appCanEnterPip,
             RemoteAnimationTarget runningTaskTarget) {
-        if (mActivity == null) {
+        if (mContainer == null) {
             mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                     isPresent -> mRecentsView.startHome());
             return new HomeAnimationFactory() {
@@ -86,12 +88,15 @@
 
         final View workspaceView = findWorkspaceView(launchCookies,
                 mRecentsView.getRunningTaskView());
-        boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow()
-                && workspaceView.getHeight() > 0;
+        boolean canUseWorkspaceView = workspaceView != null
+                && workspaceView.isAttachedToWindow()
+                && workspaceView.getHeight() > 0
+                && (mContainer.getDesktopVisibilityController() == null
+                || !mContainer.getDesktopVisibilityController().areDesktopTasksVisible());
 
-        mActivity.getRootView().setForceHideBackArrow(true);
+        mContainer.getRootView().setForceHideBackArrow(true);
         if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            mActivity.setHintUserWillBeActive();
+            mContainer.setHintUserWillBeActive();
         }
 
         if (!canUseWorkspaceView || appCanEnterPip || mIsSwipeForSplit) {
@@ -106,10 +111,10 @@
 
     private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
         RectF iconLocation = new RectF();
-        FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, null,
-                mActivity.getTaskbarUIController() == null
+        FloatingIconView floatingIconView = getFloatingIconView(mContainer, workspaceView, null,
+                mContainer.getTaskbarUIController() == null
                         ? null
-                        : mActivity.getTaskbarUIController().findMatchingView(workspaceView),
+                        : mContainer.getTaskbarUIController().findMatchingView(workspaceView),
                 true /* hideOriginal */, iconLocation, false /* isOpening */);
 
         // We want the window alpha to be 0 once this threshold is met, so that the
@@ -117,6 +122,10 @@
         float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
 
         return new FloatingViewHomeAnimationFactory(floatingIconView) {
+            @Nullable
+            private RectF mTargetRect;
+            @Nullable
+            private RectFSpringAnim mSiblingAnimation;
 
             @Nullable
             @Override
@@ -133,15 +142,36 @@
             @NonNull
             @Override
             public RectF getWindowTargetRect() {
-                return iconLocation;
+                if (enableScalingRevealHomeAnimation()) {
+                    if (mTargetRect == null) {
+                        mTargetRect = new RectF(iconLocation);
+                    }
+                    return mTargetRect;
+                } else {
+                    return iconLocation;
+                }
+            }
+
+            @Override
+            public void playAtomicAnimation(float velocity) {
+                if (enableScalingRevealHomeAnimation()) {
+                    if (mContainer != null) {
+                        new ScalingWorkspaceRevealAnim(
+                                mContainer, mSiblingAnimation, getWindowTargetRect()).start();
+                    }
+                } else {
+                    super.playAtomicAnimation(velocity);
+                }
             }
 
             @Override
             public void setAnimation(RectFSpringAnim anim) {
                 super.setAnimation(anim);
-                anim.addAnimatorListener(floatingIconView);
-                floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
-                floatingIconView.setFastFinishRunnable(anim::end);
+                mSiblingAnimation = anim;
+                mSiblingAnimation.addAnimatorListener(floatingIconView);
+                floatingIconView.setOnTargetChangeListener(
+                        mSiblingAnimation::onTargetPositionChanged);
+                floatingIconView.setFastFinishRunnable(mSiblingAnimation::end);
             }
 
             @Override
@@ -169,7 +199,7 @@
         Size windowSize = new Size(crop.width(), crop.height());
         int fallbackBackgroundColor =
                 FloatingWidgetView.getDefaultBackgroundColor(mContext, runningTaskTarget);
-        FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mActivity,
+        FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mContainer,
                 hostView, backgroundLocation, windowSize, tvs.getCurrentCornerRadius(),
                 isTargetTranslucent, fallbackBackgroundColor);
 
@@ -246,7 +276,7 @@
             }
         }
 
-        return mActivity.getFirstMatchForAppClose(launchCookieItemId,
+        return mContainer.getFirstMatchForAppClose(launchCookieItemId,
                 runningTaskView.getTask().key.getComponent().getPackageName(),
                 UserHandle.of(runningTaskView.getTask().key.userId),
                 false /* supportsAllAppsState */);
@@ -290,13 +320,13 @@
             // Return an empty APC here since we have an non-user controlled animation
             // to home.
             long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
-            return mActivity.getStateManager().createAnimationToNewWorkspace(
+            return mContainer.getStateManager().createAnimationToNewWorkspace(
                     NORMAL, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
         }
 
         @Override
         public void playAtomicAnimation(float velocity) {
-            new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+            new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
                     getViewIgnoredInWorkspaceRevealAnimation())
                     .start();
         }
diff --git a/quickstep/src/com/android/quickstep/NavHandle.java b/quickstep/src/com/android/quickstep/NavHandle.java
new file mode 100644
index 0000000..da3311f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/NavHandle.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.Context;
+
+import com.android.launcher3.R;
+
+/**
+ * Control and get information about the gesture nav bar at the bottom of the screen, which has
+ * historically been drawn by SysUI, but is also emulated by the stashed Taskbar on large screens.
+ */
+public interface NavHandle {
+
+    /**
+     * Animate the nav bar being long-pressed.
+     *
+     * @param isTouchDown {@code true} if the button is starting to be pressed ({@code false} if
+     *                                released or canceled)
+     * @param shrink {@code true} if the handle should shrink, {@code false} if it should grow
+     * @param durationMs how long the animation should take (for the {@code isTouchDown} case, this
+     *                   should be the same as the amount of time to trigger a long-press)
+     */
+    void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs);
+
+    /** @return {@code true} if this nav handle is actually the stashed taskbar */
+    default boolean isNavHandleStashedTaskbar() {
+        return false;
+    }
+
+    /** @return {@code true} if this nav handle can currently accept long presses */
+    default boolean canNavHandleBeLongPressed() {
+        return true;
+    }
+
+    /** @return the width of this nav handle, in pixels */
+    default int getNavHandleWidth(Context context) {
+        return context.getResources().getDimensionPixelSize(R.dimen.navigation_home_handle_width);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 31fe791..68923ee 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -15,22 +15,23 @@
  */
 package com.android.quickstep;
 
+import static com.android.launcher3.PagedView.INVALID_PAGE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 
-import android.annotation.TargetApi;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.content.Intent;
 import android.graphics.PointF;
-import android.os.Build;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.view.View;
 
 import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StatefulActivity;
@@ -39,6 +40,7 @@
 import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -50,7 +52,6 @@
 /**
  * Helper class to handle various atomic commands for switching between Overview.
  */
-@TargetApi(Build.VERSION_CODES.P)
 public class OverviewCommandHelper {
 
     public static final int TYPE_SHOW = 1;
@@ -77,7 +78,7 @@
      * do not lose the focus across multiple calls of
      * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
      */
-    private int mTaskFocusIndexOverride = -1;
+    private int mKeyboardTaskFocusIndex = -1;
 
     /**
      * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
@@ -191,15 +192,18 @@
      * Executes the task and returns true if next task can be executed. If false, then the next
      * task is deferred until {@link #scheduleNextTask} is called
      */
-    private <T extends StatefulActivity<?>> boolean executeCommand(CommandInfo cmd) {
+    private <T extends StatefulActivity<?> & RecentsViewContainer> boolean executeCommand(
+            CommandInfo cmd) {
         if (mWaitForToggleCommandComplete && cmd.type == TYPE_TOGGLE) {
             return true;
         }
         BaseActivityInterface<?, T> activityInterface =
                 mOverviewComponentObserver.getActivityInterface();
-        RecentsView recents = activityInterface.getVisibleRecentsView();
-        if (recents == null) {
-            T activity = activityInterface.getCreatedActivity();
+        RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView();
+        RecentsView createdRecentsView;
+        if (visibleRecentsView == null) {
+            T activity = activityInterface.getCreatedContainer();
+            createdRecentsView = activity == null ? null : activity.getOverviewPanel();
             DeviceProfile dp = activity == null ? null : activity.getDeviceProfile();
             TaskbarUIController uiController = activityInterface.getTaskbarController();
             boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
@@ -207,62 +211,98 @@
                     && dp != null
                     && (dp.isTablet || dp.isTwoPanels);
 
-            if (cmd.type == TYPE_HIDE) {
-                if (!allowQuickSwitch) {
+            switch (cmd.type) {
+                case TYPE_HIDE:
+                    if (!allowQuickSwitch) {
+                        return true;
+                    }
+                    mKeyboardTaskFocusIndex = uiController.launchFocusedTask();
+                    if (mKeyboardTaskFocusIndex == -1) {
+                        return true;
+                    }
+                    break;
+                case TYPE_KEYBOARD_INPUT:
+                    if (allowQuickSwitch) {
+                        uiController.openQuickSwitchView();
+                        return true;
+                    } else {
+                        mKeyboardTaskFocusIndex = 0;
+                        break;
+                    }
+                case TYPE_HOME:
+                    ActiveGestureLog.INSTANCE.addLog(
+                            "OverviewCommandHelper.executeCommand(TYPE_HOME)");
+                    mService.startActivity(mOverviewComponentObserver.getHomeIntent());
                     return true;
-                }
-                mTaskFocusIndexOverride = uiController.launchFocusedTask();
-                if (mTaskFocusIndexOverride == -1) {
-                    return true;
-                }
-            }
-            if (cmd.type == TYPE_KEYBOARD_INPUT && allowQuickSwitch) {
-                uiController.openQuickSwitchView();
-                return true;
-            }
-            if (cmd.type == TYPE_HOME) {
-                ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(TYPE_HOME)");
-                mService.startActivity(mOverviewComponentObserver.getHomeIntent());
-                return true;
+                case TYPE_SHOW:
+                    // When Recents is not currently visible, the command's type is TYPE_SHOW
+                    // when overview is triggered via the keyboard overview button or Action+Tab
+                    // keys (Not Alt+Tab which is KQS). The overview button on-screen in 3-button
+                    // nav is TYPE_TOGGLE.
+                    mKeyboardTaskFocusIndex = 0;
+                    break;
+                default:
+                    // continue below to handle displaying Recents.
             }
         } else {
+            createdRecentsView = visibleRecentsView;
             switch (cmd.type) {
                 case TYPE_SHOW:
                     // already visible
                     return true;
+                case TYPE_KEYBOARD_INPUT: {
+                    if (visibleRecentsView.isHandlingTouch()) {
+                        return true;
+                    }
+                }
                 case TYPE_HIDE: {
-                    mTaskFocusIndexOverride = -1;
-                    int currentPage = recents.getNextPage();
-                    TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount())
-                            ? (TaskView) recents.getPageAt(currentPage)
+                    if (visibleRecentsView.isHandlingTouch()) {
+                        return true;
+                    }
+                    mKeyboardTaskFocusIndex = INVALID_PAGE;
+                    int currentPage = visibleRecentsView.getNextPage();
+                    TaskView tv = (currentPage >= 0
+                            && currentPage < visibleRecentsView.getTaskViewCount())
+                            ? (TaskView) visibleRecentsView.getPageAt(currentPage)
                             : null;
-                    return launchTask(recents, tv, cmd);
+                    return launchTask(visibleRecentsView, tv, cmd);
                 }
                 case TYPE_TOGGLE:
-                    return launchTask(recents, getNextTask(recents), cmd);
+                    return launchTask(visibleRecentsView, getNextTask(visibleRecentsView), cmd);
                 case TYPE_HOME:
-                    recents.startHome();
+                    visibleRecentsView.startHome();
                     return true;
             }
         }
 
-        final Runnable completeCallback = () -> {
-            RecentsView rv = activityInterface.getVisibleRecentsView();
-            if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
-                updateRecentsViewFocus(rv);
+        if (createdRecentsView != null) {
+            createdRecentsView.setKeyboardTaskFocusIndex(mKeyboardTaskFocusIndex);
+        }
+        // Handle recents view focus when launching from home
+        Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                updateRecentsViewFocus(cmd);
             }
-            scheduleNextTask(cmd);
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                onRecentsViewFocusUpdated(cmd);
+                scheduleNextTask(cmd);
+            }
         };
-        if (activityInterface.switchToRecentsIfVisible(completeCallback)) {
+        if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
             // If successfully switched, wait until animation finishes
             return false;
         }
 
-        final T activity = activityInterface.getCreatedActivity();
+        final T activity = activityInterface.getCreatedContainer();
         if (activity != null) {
             InteractionJankMonitorWrapper.begin(
                     activity.getRootView(),
-                    InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+                    Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
         }
 
         GestureState gestureState = mService.createGestureState(GestureState.DEFAULT_STATE,
@@ -272,12 +312,13 @@
                 .newHandler(gestureState, cmd.createTime);
         interactionHandler.setGestureEndCallback(
                 () -> onTransitionComplete(cmd, interactionHandler));
-        interactionHandler.initWhenReady();
+        interactionHandler.initWhenReady("OverviewCommandHelper: cmd.type=" + cmd.type);
 
         RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() {
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
                     RecentsAnimationTargets targets) {
+                updateRecentsViewFocus(cmd);
                 activityInterface.runOnInitBackgroundStateUI(() ->
                         interactionHandler.onGestureEnded(0, new PointF()));
                 cmd.removeListener(this);
@@ -288,18 +329,16 @@
                 interactionHandler.onGestureCancelled();
                 cmd.removeListener(this);
 
-                T createdActivity = activityInterface.getCreatedActivity();
+                T createdActivity = activityInterface.getCreatedContainer();
                 if (createdActivity == null) {
                     return;
                 }
-                RecentsView createdRecents = createdActivity.getOverviewPanel();
-                if (createdRecents != null) {
-                    createdRecents.onRecentsAnimationComplete();
+                if (createdRecentsView != null) {
+                    createdRecentsView.onRecentsAnimationComplete();
                 }
             }
         };
 
-        RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
         if (visibleRecentsView != null) {
             visibleRecentsView.moveRunningTaskToFront();
         }
@@ -319,7 +358,6 @@
             interactionHandler.onGestureStarted(false /*isLikelyToStartNewTask*/);
             cmd.mActiveCallbacks.addListener(recentAnimListener);
         }
-
         Trace.beginAsyncSection(TRANSITION_NAME, 0);
         return false;
     }
@@ -327,47 +365,59 @@
     private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) {
         cmd.removeListener(handler);
         Trace.endAsyncSection(TRANSITION_NAME, 0);
-
-        RecentsView rv =
-                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
-        if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
-            updateRecentsViewFocus(rv);
-        }
+        onRecentsViewFocusUpdated(cmd);
         scheduleNextTask(cmd);
     }
 
-    private void updateRecentsViewFocus(@NonNull RecentsView rv) {
+    private void updateRecentsViewFocus(CommandInfo cmd) {
+        RecentsView recentsView =
+                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
+        if (recentsView == null || (cmd.type != TYPE_KEYBOARD_INPUT && cmd.type != TYPE_HIDE
+                && cmd.type != TYPE_SHOW)) {
+            return;
+        }
         // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
         // the touch mode somehow is not change to false by the Android framework.
         // The subsequent tab to go through tasks in overview can only be dispatched to
         // focuses views, while focus can only be requested in
         // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
         // here we launch overview with live tile.
-        rv.getViewRootImpl().touchModeChanged(false);
+        recentsView.getViewRootImpl().touchModeChanged(false);
         // Ensure that recents view has focus so that it receives the followup key inputs
-        TaskView taskView = rv.getTaskViewAt(mTaskFocusIndexOverride);
-        if (taskView != null) {
-            requestFocus(taskView);
+        if (requestFocus(recentsView.getTaskViewAt(mKeyboardTaskFocusIndex))) {
             return;
         }
-        taskView = rv.getNextTaskView();
-        if (taskView != null) {
-            requestFocus(taskView);
+        if (requestFocus(recentsView.getNextTaskView())) {
             return;
         }
-        taskView = rv.getTaskViewAt(0);
-        if (taskView != null) {
-            requestFocus(taskView);
+        if (requestFocus(recentsView.getTaskViewAt(0))) {
             return;
         }
-        requestFocus(rv);
+        requestFocus(recentsView);
     }
 
-    private void requestFocus(@NonNull View view) {
-        view.post(() -> {
-            view.requestFocus();
-            view.requestAccessibilityFocus();
+    private void onRecentsViewFocusUpdated(CommandInfo cmd) {
+        RecentsView recentsView =
+                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
+        if (recentsView == null
+                || cmd.type != TYPE_HIDE
+                || mKeyboardTaskFocusIndex == INVALID_PAGE) {
+            return;
+        }
+        recentsView.setKeyboardTaskFocusIndex(INVALID_PAGE);
+        recentsView.setCurrentPage(mKeyboardTaskFocusIndex);
+        mKeyboardTaskFocusIndex = INVALID_PAGE;
+    }
+
+    private boolean requestFocus(@Nullable View taskView) {
+        if (taskView == null) {
+            return false;
+        }
+        taskView.post(() -> {
+            taskView.requestFocus();
+            taskView.requestAccessibilityFocus();
         });
+        return true;
     }
 
     public void dump(PrintWriter pw) {
@@ -376,7 +426,7 @@
         if (!mPendingCommands.isEmpty()) {
             pw.println("    pendingCommandType=" + mPendingCommands.get(0).type);
         }
-        pw.println("  mTaskFocusIndexOverride=" + mTaskFocusIndexOverride);
+        pw.println("  mKeyboardTaskFocusIndex=" + mKeyboardTaskFocusIndex);
         pw.println("  mWaitForToggleCommandComplete=" + mWaitForToggleCommandComplete);
     }
 
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index d1939ef..3c902e6 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -15,10 +15,8 @@
  */
 package com.android.quickstep;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.os.Build;
 import android.os.Looper;
 import android.os.Trace;
 import android.os.UserManager;
@@ -30,7 +28,6 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 @SuppressWarnings("unused")
-@TargetApi(Build.VERSION_CODES.R)
 public class QuickstepProcessInitializer extends MainProcessInitializer {
 
     private static final String TAG = "QuickstepProcessInitializer";
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 0303791..dfbae65 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -1,5 +1,6 @@
 package com.android.quickstep;
 
+import static com.android.launcher3.taskbar.TaskbarThresholdUtils.getFromNavThreshold;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.app.Activity;
@@ -10,17 +11,20 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.R;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.testing.TestInformationHandler;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.TISBindHelper;
+import com.android.quickstep.views.RecentsView;
 
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
@@ -36,6 +40,30 @@
     public Bundle call(String method, String arg, @Nullable Bundle extras) {
         final Bundle response = new Bundle();
         switch (method) {
+            case TestProtocol.REQUEST_RECENT_TASKS_LIST: {
+                ArrayList<String> taskBaseIntentComponents = new ArrayList<>();
+                CountDownLatch latch = new CountDownLatch(1);
+                RecentsModel.INSTANCE.get(mContext).getTasks((taskGroups) -> {
+                    for (GroupTask group : taskGroups) {
+                        taskBaseIntentComponents.add(
+                                group.task1.key.baseIntent.getComponent().flattenToString());
+                        if (group.task2 != null) {
+                            taskBaseIntentComponents.add(
+                                    group.task2.key.baseIntent.getComponent().flattenToString());
+                        }
+                    }
+                    latch.countDown();
+                });
+                try {
+                    latch.await(2, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+                response.putStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        taskBaseIntentComponents);
+                return response;
+            }
+
             case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
                 final float swipeHeight =
                         LayoutUtils.getDefaultSwipeHeight(mContext, mDeviceProfile);
@@ -55,7 +83,7 @@
                 }
                 Rect focusedTaskRect = new Rect();
                 LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
-                        focusedTaskRect, PagedOrientationHandler.PORTRAIT);
+                        focusedTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
                 return response;
             }
@@ -66,7 +94,7 @@
                 }
                 Rect gridTaskRect = new Rect();
                 LauncherActivityInterface.INSTANCE.calculateGridTaskSize(mContext, mDeviceProfile,
-                        gridTaskRect, PagedOrientationHandler.PORTRAIT);
+                        gridTaskRect, RecentsPagedOrientationHandler.PORTRAIT);
                 response.putParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD, gridTaskRect);
                 return response;
             }
@@ -77,6 +105,11 @@
                 return response;
             }
 
+            case TestProtocol.REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX: {
+                return getLauncherUIProperty(Bundle::putInt,
+                        launcher -> launcher.<RecentsView>getOverviewPanel().getCurrentPage());
+            }
+
             case TestProtocol.REQUEST_HAS_TIS: {
                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true);
                 return response;
@@ -93,7 +126,7 @@
             case TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD: {
                 final Resources resources = mContext.getResources();
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        resources.getDimensionPixelSize(R.dimen.taskbar_from_nav_threshold));
+                        getFromNavThreshold(resources, mDeviceProfile));
                 return response;
             }
 
@@ -149,6 +182,22 @@
             case TestProtocol.REQUEST_REFRESH_OVERVIEW_TARGET:
                 runOnTISBinder(TouchInteractionService.TISBinder::refreshOverviewTarget);
                 return response;
+
+            case TestProtocol.REQUEST_RECREATE_TASKBAR:
+                // Allow null-pointer to catch illegal states.
+                runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
+                return response;
+            case TestProtocol.REQUEST_TASKBAR_IME_DOCKED:
+                return getTISBinderUIProperty(Bundle::putBoolean, tisBinder ->
+                        tisBinder.getTaskbarManager()
+                                .getCurrentActivityContext().isImeDocked());
+            case TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED:
+                runOnTISBinder(tisBinder -> {
+                    // Allow null-pointer to catch illegal states.
+                    tisBinder.getTaskbarManager().getCurrentActivityContext()
+                            .unstashBubbleBarIfStashed();
+                });
+                return response;
         }
 
         return super.call(method, arg, extras);
@@ -159,7 +208,7 @@
         RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext);
         OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads);
         try {
-            return observer.getActivityInterface().getCreatedActivity();
+            return observer.getActivityInterface().getCreatedContainer();
         } finally {
             observer.onDestroy();
             rads.destroy();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 7c263b8..711882c 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,15 +20,13 @@
 
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
 
-import android.annotation.TargetApi;
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.TaskInfo;
 import android.content.ComponentName;
-import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.SparseBooleanArray;
@@ -53,7 +51,6 @@
 /**
  * Manages the recent task list from the system, caching it as necessary.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class RecentTasksList {
 
     private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
@@ -100,6 +97,13 @@
                     RecentTasksList.this.onRunningTaskVanished(taskInfo);
                 });
             }
+
+            @Override
+            public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+                mMainThreadExecutor.execute(() -> {
+                    RecentTasksList.this.onRunningTaskChanged(taskInfo);
+                });
+            }
         });
         // We may receive onRunningTaskAppeared events later for tasks which have already been
         // included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
@@ -247,6 +251,20 @@
         }
     }
 
+    private void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+        // Find the task from the list of running tasks, if it exists
+        for (ActivityManager.RunningTaskInfo existingTask : mRunningTasks) {
+            if (existingTask.taskId != taskInfo.taskId) continue;
+
+            mRunningTasks.remove(existingTask);
+            mRunningTasks.add(taskInfo);
+            if (mRunningTasksListener != null) {
+                mRunningTasksListener.onRunningTasksChanged();
+            }
+            return;
+        }
+    }
+
     /**
      * Loads and creates a list of all the recent tasks.
      */
@@ -273,9 +291,13 @@
 
         int numVisibleTasks = 0;
         for (GroupedRecentTaskInfo rawTask : rawTasks) {
-            if (isDesktopModeSupported() && rawTask.getType() == TYPE_FREEFORM) {
-                GroupTask desktopTask = createDesktopTask(rawTask);
-                allTasks.add(desktopTask);
+            if (rawTask.getType() == TYPE_FREEFORM) {
+                // TYPE_FREEFORM tasks is only created when enableDesktopWindowingMode() is true,
+                // leftover TYPE_FREEFORM tasks created when flag was on should be ignored.
+                if (enableDesktopWindowingMode()) {
+                    GroupTask desktopTask = createDesktopTask(rawTask);
+                    allTasks.add(desktopTask);
+                }
                 continue;
             }
             ActivityManager.RecentTaskInfo taskInfo1 = rawTask.getTaskInfo1();
@@ -389,4 +411,4 @@
             return mRequestId == requestId && (!mKeysOnly || loadKeysOnly);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 22163b9..f57f4c8 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -27,12 +27,13 @@
 import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.app.ActivityOptions;
+import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
@@ -85,6 +86,7 @@
 import com.android.quickstep.util.TISBindHelper;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskView;
 
 import java.io.FileDescriptor;
@@ -95,7 +97,8 @@
  * A recents activity that shows the recently launched tasks as swipable task cards.
  * See {@link com.android.quickstep.views.RecentsView}.
  */
-public final class RecentsActivity extends StatefulActivity<RecentsState> {
+public final class RecentsActivity extends StatefulActivity<RecentsState> implements
+        RecentsViewContainer {
     private static final String TAG = "RecentsActivity";
 
     public static final ActivityTracker<RecentsActivity> ACTIVITY_TRACKER =
@@ -109,7 +112,7 @@
     private RecentsDragLayer mDragLayer;
     private ScrimView mScrimView;
     private FallbackRecentsView mFallbackRecentsView;
-    private OverviewActionsView mActionsView;
+    private OverviewActionsView<?> mActionsView;
     private TISBindHelper mTISBindHelper;
     private @Nullable FallbackTaskbarUIController mTaskbarUIController;
 
@@ -144,7 +147,7 @@
                         systemUiProxy, RecentsModel.INSTANCE.get(this),
                         null /*activityBackCallback*/);
         mDragLayer.recreateControllers();
-        if (isDesktopModeSupported()) {
+        if (enableDesktopWindowingMode()) {
             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
                     getStateManager(), systemUiProxy, getIApplicationThread(),
                     null /* depthController */
@@ -224,11 +227,12 @@
     }
 
     @Override
-    public <T extends View> T getOverviewPanel() {
-        return (T) mFallbackRecentsView;
+    public FallbackRecentsView getOverviewPanel() {
+        return mFallbackRecentsView;
     }
 
-    public OverviewActionsView getActionsView() {
+    @Override
+    public OverviewActionsView<?> getActionsView() {
         return mActionsView;
     }
 
@@ -498,4 +502,9 @@
         OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper();
         return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely();
     }
+
+    @NonNull
+    public TISBindHelper getTISBindHelper() {
+        return mTISBindHelper;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 5d26ec0..da7a98f 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -39,6 +39,7 @@
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -219,6 +220,13 @@
         }
     }
 
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RecentsAnimationCallbacks:");
+
+        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+        pw.println(prefix + "\tmCancelled=" + mCancelled);
+    }
+
     /**
      * Listener for the recents animation callbacks.
      */
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 341e18c..1b05e28 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -25,14 +25,13 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.IRecentsAnimationController;
-import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.WindowManagerGlobal;
 import android.window.PictureInPictureSurfaceTransaction;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.UiThread;
 
+import com.android.internal.jank.Cuj;
 import com.android.internal.os.IResultReceiver;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.RunnableList;
@@ -42,6 +41,7 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
 
+import java.io.PrintWriter;
 import java.util.function.Consumer;
 
 /**
@@ -183,10 +183,9 @@
                     });
                 }
             });
-            InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
-            InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
-            InteractionJankMonitorWrapper.end(
-                    InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         };
         if (forceFinish) {
             finishCb.run();
@@ -269,4 +268,14 @@
     public boolean getFinishTargetIsLauncher() {
         return mFinishTargetIsLauncher;
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RecentsAnimationController:");
+
+        pw.println(prefix + "\tmAllowMinimizeSplitScreen=" + mAllowMinimizeSplitScreen);
+        pw.println(prefix + "\tmUseLauncherSysBarFlags=" + mUseLauncherSysBarFlags);
+        pw.println(prefix + "\tmSplitScreenMinimized=" + mSplitScreenMinimized);
+        pw.println(prefix + "\tmFinishRequested=" + mFinishRequested);
+        pw.println(prefix + "\tmFinishTargetIsLauncher=" + mFinishTargetIsLauncher);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 179612b..4b4f914 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -19,11 +19,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
 import static com.android.launcher3.util.NavigationMode.THREE_BUTTONS;
 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED;
@@ -55,19 +53,13 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.provider.Settings;
-import android.util.Log;
-import android.view.ISystemGestureExclusionListener;
-import android.view.IWindowManager;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
-import android.view.WindowManagerGlobal;
 
-import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
@@ -75,6 +67,9 @@
 import com.android.launcher3.util.SettingsCache;
 import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
 import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.util.AssistStateManager;
+import com.android.quickstep.util.GestureExclusionManager;
+import com.android.quickstep.util.GestureExclusionManager.ExclusionListener;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -88,7 +83,7 @@
 /**
  * Manages the state of the system during a swipe up gesture.
  */
-public class RecentsAnimationDeviceState implements DisplayInfoChangeListener {
+public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, ExclusionListener {
 
     private static final String TAG = "RecentsAnimationDeviceState";
 
@@ -101,25 +96,9 @@
     private final Context mContext;
     private final DisplayController mDisplayController;
 
-    private final IWindowManager mIWindowManager;
+    private final GestureExclusionManager mExclusionManager;
+    private final AssistStateManager mAssistStateManager;
 
-    @VisibleForTesting
-    final ISystemGestureExclusionListener mGestureExclusionListener =
-            new ISystemGestureExclusionListener.Stub() {
-                @BinderThread
-                @Override
-                public void onSystemGestureExclusionChanged(int displayId,
-                        Region systemGestureExclusionRegion, Region unrestrictedOrNull) {
-                    if (displayId != DEFAULT_DISPLAY) {
-                        return;
-                    }
-                    // Assignments are atomic, it should be safe on binder thread. Also we don't
-                    // think systemGestureExclusionRegion can be null but just in case, don't
-                    // let mExclusionRegion be null.
-                    mExclusionRegion = systemGestureExclusionRegion != null
-                            ? systemGestureExclusionRegion : new Region();
-                }
-            };
     private final RotationTouchHelper mRotationTouchHelper;
     private final TaskStackChangeListener mPipListener;
     // Cache for better performance since it doesn't change at runtime.
@@ -140,22 +119,23 @@
     private boolean mIsSwipeToNotificationEnabled;
     private final boolean mIsOneHandedModeSupported;
     private boolean mPipIsActive;
+    private boolean mIsPredictiveBackToHomeInProgress;
 
     private int mGestureBlockingTaskId = -1;
-    private @NonNull Region mExclusionRegion = new Region();
+    private @NonNull Region mExclusionRegion = GestureExclusionManager.EMPTY_REGION;
     private boolean mExclusionListenerRegistered;
 
     public RecentsAnimationDeviceState(Context context) {
-        this(context, false, WindowManagerGlobal.getWindowManagerService());
+        this(context, false, GestureExclusionManager.INSTANCE);
     }
 
     public RecentsAnimationDeviceState(Context context, boolean isInstanceForTouches) {
-        this(context, isInstanceForTouches, WindowManagerGlobal.getWindowManagerService());
+        this(context, isInstanceForTouches, GestureExclusionManager.INSTANCE);
     }
 
     @VisibleForTesting
-    RecentsAnimationDeviceState(Context context, IWindowManager windowManager) {
-        this(context, false, windowManager);
+    RecentsAnimationDeviceState(Context context, GestureExclusionManager exclusionManager) {
+        this(context, false, exclusionManager);
     }
 
     /**
@@ -164,10 +144,11 @@
      */
     RecentsAnimationDeviceState(
             Context context, boolean isInstanceForTouches,
-            IWindowManager windowManager) {
+            GestureExclusionManager exclusionManager) {
         mContext = context;
         mDisplayController = DisplayController.INSTANCE.get(context);
-        mIWindowManager = windowManager;
+        mExclusionManager = exclusionManager;
+        mAssistStateManager = AssistStateManager.INSTANCE.get(context);
         mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
         mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
         if (isInstanceForTouches) {
@@ -278,43 +259,33 @@
         }
     }
 
-    /**
-     * Registers {@link mGestureExclusionListener} for getting exclusion rect changes. Note that we
-     * make binder call on {@link UI_HELPER_EXECUTOR} to avoid jank.
-     */
-    public void registerExclusionListener() {
-        UI_HELPER_EXECUTOR.execute(() -> {
-            if (mExclusionListenerRegistered) {
-                return;
-            }
-            try {
-                mIWindowManager.registerSystemGestureExclusionListener(
-                        mGestureExclusionListener, DEFAULT_DISPLAY);
-                mExclusionListenerRegistered = true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to register window manager callbacks", e);
-            }
-        });
+    @Override
+    public void onGestureExclusionChanged(@Nullable Region exclusionRegion,
+            @Nullable Region unrestrictedOrNull) {
+        mExclusionRegion = exclusionRegion != null
+                ? exclusionRegion : GestureExclusionManager.EMPTY_REGION;
     }
 
     /**
-     * Unregisters {@link mGestureExclusionListener} if previously registered. We make binder call
-     * on same {@link UI_HELPER_EXECUTOR} as in {@link #registerExclusionListener()} so that
-     * read/write {@link mExclusionListenerRegistered} field is thread safe.
+     * Registers itself for getting exclusion rect changes.
+     */
+    public void registerExclusionListener() {
+        if (mExclusionListenerRegistered) {
+            return;
+        }
+        mExclusionManager.addListener(this);
+        mExclusionListenerRegistered = true;
+    }
+
+    /**
+     * Unregisters itself as gesture exclusion listener if previously registered.
      */
     public void unregisterExclusionListener() {
-        UI_HELPER_EXECUTOR.execute(() -> {
-            if (!mExclusionListenerRegistered) {
-                return;
-            }
-            try {
-                mIWindowManager.unregisterSystemGestureExclusionListener(
-                        mGestureExclusionListener, DEFAULT_DISPLAY);
-                mExclusionListenerRegistered = false;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to unregister window manager callbacks", e);
-            }
-        });
+        if (!mExclusionListenerRegistered) {
+            return;
+        }
+        mExclusionManager.removeListener(this);
+        mExclusionListenerRegistered = false;
     }
 
     public void onOneHandedModeChanged(int newGesturalHeight) {
@@ -393,6 +364,20 @@
     }
 
     /**
+     * Sets the flag that indicates whether a predictive back-to-home animation is in progress
+     */
+    public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
+        mIsPredictiveBackToHomeInProgress = isInProgress;
+    }
+
+    /**
+     * @return whether a predictive back-to-home animation is currently in progress
+     */
+    public boolean isPredictiveBackToHomeInProgress() {
+        return mIsPredictiveBackToHomeInProgress;
+    }
+
+    /**
      * @return whether SystemUI is in a state where we can start a system gesture.
      */
     public boolean canStartSystemGesture() {
@@ -517,10 +502,8 @@
      *         This is only used for quickswitch, and not swipe up.
      */
     public boolean isInExclusionRegion(MotionEvent event) {
-        // mExclusionRegion can change on binder thread, use a local instance here.
-        Region exclusionRegion = mExclusionRegion;
         return mMode == NO_BUTTON
-                && exclusionRegion.contains((int) event.getX(), (int) event.getY());
+                && mExclusionRegion.contains((int) event.getX(), (int) event.getY());
     }
 
     /**
@@ -606,9 +589,8 @@
                 : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
         float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
 
-        if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
-            float customSlopMultiplier =
-                    LauncherPrefs.get(mContext).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
+        if (mAssistStateManager.getLPNHCustomSlopMultiplier().isPresent()) {
+            float customSlopMultiplier = mAssistStateManager.getLPNHCustomSlopMultiplier().get();
             return customSlopMultiplier * slopMultiplier * touchSlop;
         } else {
             return slopMultiplier * touchSlop;
@@ -642,6 +624,7 @@
         pw.println("  deferredGestureRegion=" + mDeferredGestureRegion.getBounds());
         pw.println("  exclusionRegion=" + mExclusionRegion.getBounds());
         pw.println("  pipIsActive=" + mPipIsActive);
+        pw.println("  predictiveBackToHomeInProgress=" + mIsPredictiveBackToHomeInProgress);
         mRotationTouchHelper.dump(pw);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 556dd7e..82bb453 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -17,13 +17,16 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 
 import android.app.WindowConfiguration;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
+import java.io.PrintWriter;
+
 /**
  * Extension of {@link RemoteAnimationTargets} with additional information about swipe
  * up animation
@@ -52,7 +55,7 @@
      * @return {@code true} if at least one target app is a desktop task
      */
     public boolean hasDesktopTasks() {
-        if (!isDesktopModeSupported()) {
+        if (!enableDesktopWindowingMode()) {
             return false;
         }
         for (RemoteAnimationTarget target : apps) {
@@ -62,4 +65,14 @@
         }
         return false;
     }
+
+    @Override
+    public void dump(String prefix, PrintWriter pw) {
+        super.dump(prefix, pw);
+        prefix += '\t';
+        pw.println(prefix + "RecentsAnimationTargets:");
+
+        pw.println(prefix + "\thomeContentInsets=" + homeContentInsets);
+        pw.println(prefix + "\tminimizedHomeBounds=" + minimizedHomeBounds);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index e0c7403..57edd82 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -149,6 +150,14 @@
         }
     }
 
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "RemoteAnimationTargets:");
+
+        pw.println(prefix + "\ttargetMode=" + targetMode);
+        pw.println(prefix + "\thasRecents=" + hasRecents);
+        pw.println(prefix + "\tmReleased=" + mReleased);
+    }
+
     /**
      * Interface for intercepting surface release method
      */
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 98d0ece..3dec381 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,16 +17,18 @@
 package com.android.quickstep;
 
 import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
 
+import android.app.WindowConfiguration;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.TaskViewSimulator;
@@ -35,6 +37,8 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Glues together the necessary components to animate a remote target using a
@@ -43,7 +47,9 @@
 public class RemoteTargetGluer {
     private static final String TAG = "RemoteTargetGluer";
 
-    private static final int DEFAULT_NUM_HANDLES = 2;
+    // This is the default number of handles to create when we don't know how many tasks are running
+    // (e.g. if we're in split screen). Allocate extra for potential tasks overlaid, like volume.
+    private static final int DEFAULT_NUM_HANDLES = 4;
 
     private RemoteTargetHandle[] mRemoteTargetHandles;
     private SplitConfigurationOptions.SplitBounds mSplitBounds;
@@ -51,7 +57,7 @@
     /**
      * Use this constructor if remote targets are split-screen independent
      */
-    public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy,
+    public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy,
             RemoteAnimationTargets targets, boolean forDesktop) {
         init(context, sizingStrategy, targets.apps.length, forDesktop);
     }
@@ -60,14 +66,15 @@
      * Use this constructor if you want the number of handles created to match the number of active
      * running tasks
      */
-    public RemoteTargetGluer(Context context, BaseActivityInterface sizingStrategy) {
-        if (isDesktopModeSupported()) {
-            // TODO(279931899): binder call, only for prototyping. Creating the gluer should be
-            //  postponed so we can create it when we have the remote animation targets ready.
-            int desktopTasks = SystemUiProxy.INSTANCE.get(context).getVisibleDesktopTaskCount(
-                    context.getDisplayId());
-            if (desktopTasks > 0) {
-                init(context, sizingStrategy, desktopTasks, true /* forDesktop */);
+    public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy) {
+        DesktopVisibilityController desktopVisibilityController =
+                LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+        if (desktopVisibilityController != null) {
+            int visibleTasksCount = desktopVisibilityController.getVisibleDesktopTasksCount();
+            if (visibleTasksCount > 0) {
+                // Allocate +1 to account for a new task added to the desktop mode
+                int numHandles = visibleTasksCount + 1;
+                init(context, sizingStrategy, numHandles, true /* forDesktop */);
                 return;
             }
         }
@@ -77,13 +84,13 @@
         init(context, sizingStrategy, DEFAULT_NUM_HANDLES, false /* forDesktop */);
     }
 
-    private void init(Context context, BaseActivityInterface sizingStrategy, int numHandles,
+    private void init(Context context, BaseContainerInterface sizingStrategy, int numHandles,
             boolean forDesktop) {
         mRemoteTargetHandles = createHandles(context, sizingStrategy, numHandles, forDesktop);
     }
 
     private RemoteTargetHandle[] createHandles(Context context,
-            BaseActivityInterface sizingStrategy, int numHandles, boolean forDesktop) {
+            BaseContainerInterface sizingStrategy, int numHandles, boolean forDesktop) {
         RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles];
         for (int i = 0; i < numHandles; i++) {
             TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy);
@@ -107,7 +114,7 @@
         for (int i = 0; i < mRemoteTargetHandles.length; i++) {
             RemoteAnimationTarget primaryTaskTarget = targets.apps[i];
             mRemoteTargetHandles[i].mTransformParams.setTargetSet(
-                    createRemoteAnimationTargetsForTarget(targets, null));
+                    createRemoteAnimationTargetsForTarget(targets, Collections.emptyList()));
             mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
         }
         return mRemoteTargetHandles;
@@ -129,18 +136,7 @@
      * the left/top task, index 1 right/bottom.
      */
     public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
-        // Resize the mRemoteTargetHandles array since we started assuming split screen, but
-        // targets.apps is the ultimate source of truth here
-        long appCount = Arrays.stream(targets.apps)
-                .filter(app -> app.mode == targets.targetMode)
-                .count();
-        Log.d(TAG, "appCount: " + appCount + " handleLength: " + mRemoteTargetHandles.length);
-        if (appCount < mRemoteTargetHandles.length) {
-            Log.d(TAG, "resizing handles");
-            RemoteTargetHandle[] newHandles = new RemoteTargetHandle[(int) appCount];
-            System.arraycopy(mRemoteTargetHandles, 0/*src*/, newHandles, 0/*dst*/, (int) appCount);
-            mRemoteTargetHandles = newHandles;
-        }
+        resizeRemoteTargetHandles(targets);
 
         // If we are in a true split screen case (2 apps running on screen), either:
         //     a) mSplitBounds was already set (from the clicked GroupedTaskView)
@@ -177,18 +173,42 @@
             RemoteAnimationTarget topLeftTarget = targets.findTask(mSplitBounds.leftTopTaskId);
             RemoteAnimationTarget bottomRightTarget = targets.findTask(
                     mSplitBounds.rightBottomTaskId);
+            List<RemoteAnimationTarget> overlayTargets = Arrays.stream(targets.apps).filter(
+                    target -> target.windowConfiguration.getWindowingMode()
+                            != WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW).toList();
 
             // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude,
             // vice versa
             mRemoteTargetHandles[0].mTransformParams.setTargetSet(
-                    createRemoteAnimationTargetsForTarget(targets, bottomRightTarget));
-            mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget,
-                    mSplitBounds);
+                    createRemoteAnimationTargetsForTarget(targets,
+                            Collections.singletonList(bottomRightTarget)));
+            mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget, mSplitBounds);
 
             mRemoteTargetHandles[1].mTransformParams.setTargetSet(
-                    createRemoteAnimationTargetsForTarget(targets, topLeftTarget));
-            mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget,
-                    mSplitBounds);
+                    createRemoteAnimationTargetsForTarget(targets,
+                            Collections.singletonList(topLeftTarget)));
+            mRemoteTargetHandles[1].mTaskViewSimulator.setPreview(bottomRightTarget, mSplitBounds);
+
+            // Set the remaining overlay tasks to be their own TaskViewSimulator as fullscreen tasks
+            if (!overlayTargets.isEmpty()) {
+                ArrayList<RemoteAnimationTarget> targetsToExclude = new ArrayList<>();
+                targetsToExclude.add(topLeftTarget);
+                targetsToExclude.add(bottomRightTarget);
+                // Start i at 2 to account for top/left and bottom/right split handles already made
+                for (int i = 2; i < targets.apps.length; i++) {
+                    if (i >= mRemoteTargetHandles.length) {
+                        Log.e(TAG, String.format("Attempting to animate an untracked target"
+                                + " (%d handles allocated, but %d want to animate)",
+                                mRemoteTargetHandles.length, targets.apps.length));
+                        break;
+                    }
+                    mRemoteTargetHandles[i].mTransformParams.setTargetSet(
+                            createRemoteAnimationTargetsForTarget(targets, targetsToExclude));
+                    mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(
+                            overlayTargets.get(i - 2));
+                }
+
+            }
         }
         return mRemoteTargetHandles;
     }
@@ -198,15 +218,36 @@
      * transform params per app in {@code targets.apps} list.
      */
     public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) {
+        resizeRemoteTargetHandles(targets);
+
         for (int i = 0; i < mRemoteTargetHandles.length; i++) {
             RemoteAnimationTarget primaryTaskTarget = targets.apps[i];
+            List<RemoteAnimationTarget> excludeTargets = Arrays.stream(targets.apps)
+                    .filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
             mRemoteTargetHandles[i].mTransformParams.setTargetSet(
-                    createRemoteAnimationTargetsForTaskId(targets, primaryTaskTarget.taskId));
+                    createRemoteAnimationTargetsForTarget(targets, excludeTargets));
             mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
         }
         return mRemoteTargetHandles;
     }
 
+    /**
+     * Resize the `mRemoteTargetHandles` array since we assumed initial size, but
+     * `targets.apps` is the ultimate source of truth here
+     */
+    private void resizeRemoteTargetHandles(RemoteAnimationTargets targets) {
+        long appCount = Arrays.stream(targets.apps)
+                .filter(app -> app.mode == targets.targetMode)
+                .count();
+        Log.d(TAG, "appCount: " + appCount + " handleLength: " + mRemoteTargetHandles.length);
+        if (appCount < mRemoteTargetHandles.length) {
+            Log.d(TAG, "resizing handles");
+            RemoteTargetHandle[] newHandles = new RemoteTargetHandle[(int) appCount];
+            System.arraycopy(mRemoteTargetHandles, 0/*src*/, newHandles, 0/*dst*/, (int) appCount);
+            mRemoteTargetHandles = newHandles;
+        }
+    }
+
     private Rect getStartBounds(RemoteAnimationTarget target) {
         return target.startBounds == null ? target.screenSpaceBounds : target.startBounds;
     }
@@ -214,64 +255,43 @@
     /**
      * Ensures that we aren't excluding ancillary targets such as home/recents
      *
-     * @param targetToExclude Will be excluded from the resulting return value.
-     *                        Pass in {@code null} to not exclude anything
+     * @param targetsToExclude Will be excluded from the resulting return value.
+     *                        Pass in an empty list to not exclude anything
      * @return RemoteAnimationTargets where all the app targets from the passed in
-     *         {@param targets} are included except {@param targetToExclude}
+     *         {@code targets} are included except {@code targetsToExclude}
      */
     private RemoteAnimationTargets createRemoteAnimationTargetsForTarget(
-            RemoteAnimationTargets targets,
-            RemoteAnimationTarget targetToExclude) {
-        ArrayList<RemoteAnimationTarget> targetsWithoutExcluded = new ArrayList<>();
+            @NonNull RemoteAnimationTargets targets,
+            @NonNull List<RemoteAnimationTarget> targetsToExclude) {
+        ArrayList<RemoteAnimationTarget> targetsToInclude = new ArrayList<>();
 
         for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) {
-            if (targetCompat == targetToExclude) {
+            boolean skipTarget = false;
+            for (RemoteAnimationTarget excludingTarget : targetsToExclude) {
+                if (targetCompat == excludingTarget) {
+                    skipTarget = true;
+                    break;
+                }
+                if (excludingTarget != null
+                        && excludingTarget.taskInfo != null
+                        && targetCompat.taskInfo != null
+                        && excludingTarget.taskInfo.parentTaskId == targetCompat.taskInfo.taskId) {
+                    // Also exclude corresponding parent task
+                    skipTarget = true;
+                }
+            }
+            if (skipTarget) {
                 continue;
             }
-            if (targetToExclude != null
-                    && targetToExclude.taskInfo != null
-                    && targetCompat.taskInfo != null
-                    && targetToExclude.taskInfo.parentTaskId == targetCompat.taskInfo.taskId) {
-                // Also exclude corresponding parent task
-                continue;
-            }
-
-            targetsWithoutExcluded.add(targetCompat);
+            targetsToInclude.add(targetCompat);
         }
-        final RemoteAnimationTarget[] filteredApps = targetsWithoutExcluded.toArray(
-                new RemoteAnimationTarget[targetsWithoutExcluded.size()]);
+        final RemoteAnimationTarget[] filteredApps = targetsToInclude.toArray(
+                new RemoteAnimationTarget[0]);
         return new RemoteAnimationTargets(
                 filteredApps, targets.wallpapers, targets.nonApps, targets.targetMode);
     }
 
     /**
-     * Ensures that we only animate one specific app target. Includes ancillary targets such as
-     * home/recents
-     *
-     * @param targets remote animation targets to filter
-     * @param taskId  id for a task that we want this remote animation to apply to
-     * @return {@link RemoteAnimationTargets} where app target only includes the app that has the
-     * {@code taskId} that was passed in
-     */
-    private RemoteAnimationTargets createRemoteAnimationTargetsForTaskId(
-            RemoteAnimationTargets targets, int taskId) {
-        RemoteAnimationTarget[] targetApp = null;
-        for (RemoteAnimationTarget targetCompat : targets.unfilteredApps) {
-            if (targetCompat.taskId == taskId) {
-                targetApp = new RemoteAnimationTarget[]{targetCompat};
-                break;
-            }
-        }
-
-        if (targetApp == null) {
-            targetApp = new RemoteAnimationTarget[0];
-        }
-
-        return new RemoteAnimationTargets(targetApp, targets.wallpapers, targets.nonApps,
-                targets.targetMode);
-    }
-
-    /**
      * The object returned by this is may be modified in
      * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)}, specifically the length of the
      * array may be shortened based on the number of RemoteAnimationTargets present.
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 2d47097..3380291 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.NavigationMode;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -50,7 +51,7 @@
 /**
  * Helper class for transforming touch events
  */
-public class RotationTouchHelper implements DisplayInfoChangeListener {
+public class RotationTouchHelper implements DisplayInfoChangeListener, SafeCloseable {
 
     public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
             new MainThreadInitializedObject<>(RotationTouchHelper::new);
@@ -197,6 +198,11 @@
         mOnDestroyActions.add(action);
     }
 
+    @Override
+    public void close() {
+        destroy();
+    }
+
     /**
      * Cleans up all the registered listeners and receivers.
      */
@@ -345,14 +351,14 @@
     }
 
     void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
-            BaseActivityInterface activityInterface) {
+            BaseContainerInterface containerInterface) {
         if (endTarget == GestureState.GestureEndTarget.RECENTS) {
             mInOverview = true;
             if (!mTaskListFrozen) {
                 // If we're in landscape w/o ever quickswitching, show the navbar in landscape
                 enableMultipleRegions(true);
             }
-            activityInterface.onExitOverview(this, mExitOverviewRunnable);
+            containerInterface.onExitOverview(this, mExitOverviewRunnable);
         } else if (endTarget == GestureState.GestureEndTarget.HOME
                 || endTarget == GestureState.GestureEndTarget.ALL_APPS) {
             enableMultipleRegions(false);
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index f474796..29a57fc 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -24,22 +24,30 @@
 
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 
 public class SimpleOrientationTouchTransformer implements
-        DisplayController.DisplayInfoChangeListener {
+        DisplayController.DisplayInfoChangeListener, SafeCloseable {
 
     public static final MainThreadInitializedObject<SimpleOrientationTouchTransformer> INSTANCE =
             new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
 
+    private final Context mContext;
     private OrientationRectF mOrientationRectF;
 
     public SimpleOrientationTouchTransformer(Context context) {
+        mContext = context;
         DisplayController.INSTANCE.get(context).addChangeListener(this);
         onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
                 CHANGE_ALL);
     }
 
     @Override
+    public void close() {
+        DisplayController.INSTANCE.get(mContext).removeChangeListener(this);
+    }
+
+    @Override
     public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
         if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
             return;
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index e481165..5ff9787 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
@@ -85,7 +86,7 @@
         updateIsGestureForSplit(TopTaskTracker.INSTANCE.get(context)
                 .getRunningSplitTaskIds().length);
 
-        mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface());
+        mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getContainerInterface());
         mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles();
         runActionOnRemoteHandles(remoteTargetHandle ->
                 remoteTargetHandle.getTaskViewSimulator().getOrientationState().update(
@@ -96,9 +97,10 @@
 
     protected void initTransitionEndpoints(DeviceProfile dp) {
         mDp = dp;
-        mTransitionDragLength = mGestureState.getActivityInterface().getSwipeUpDestinationAndLength(
-                dp, mContext, TEMP_RECT, mRemoteTargetHandles[0].getTaskViewSimulator()
-                        .getOrientationState().getOrientationHandler());
+        mTransitionDragLength = mGestureState.getContainerInterface()
+                .getSwipeUpDestinationAndLength(dp, mContext, TEMP_RECT,
+                        mRemoteTargetHandles[0].getTaskViewSimulator().getOrientationState()
+                                .getOrientationHandler());
         mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
 
         for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) {
@@ -151,7 +153,7 @@
     @UiThread
     public abstract void onCurrentShiftUpdated();
 
-    protected PagedOrientationHandler getOrientationHandler() {
+    protected RecentsPagedOrientationHandler getOrientationHandler() {
         // OrientationHandler should be independent of remote target, can directly take one
         return mRemoteTargetHandles[0].getTaskViewSimulator()
                 .getOrientationState().getOrientationHandler();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 94ed5b9..ab9840f 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -16,12 +16,16 @@
 package com.android.quickstep;
 
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.content.pm.PackageManager.FEATURE_PC;
 
+import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -31,7 +35,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -62,11 +65,12 @@
 import com.android.internal.logging.InstanceId;
 import com.android.internal.util.ScreenshotRequest;
 import com.android.internal.view.AppearanceRegion;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AssistUtils;
+import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -74,27 +78,28 @@
 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
 import com.android.systemui.shared.system.smartspace.SmartspaceState;
+import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
 import com.android.systemui.unfold.progress.IUnfoldAnimation;
 import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
 import com.android.wm.shell.back.IBackAnimation;
 import com.android.wm.shell.bubbles.IBubbles;
 import com.android.wm.shell.bubbles.IBubblesListener;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.common.pip.IPip;
+import com.android.wm.shell.common.pip.IPipAnimationListener;
 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
 import com.android.wm.shell.desktopmode.IDesktopMode;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
 import com.android.wm.shell.draganddrop.IDragAndDrop;
 import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.pip.IPip;
-import com.android.wm.shell.pip.IPipAnimationListener;
 import com.android.wm.shell.recents.IRecentTasks;
 import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.IShellTransitions;
 import com.android.wm.shell.splitscreen.ISplitScreen;
 import com.android.wm.shell.splitscreen.ISplitScreenListener;
 import com.android.wm.shell.splitscreen.ISplitSelectListener;
 import com.android.wm.shell.startingsurface.IStartingWindow;
 import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.transition.IHomeTransitionListener;
-import com.android.wm.shell.transition.IShellTransitions;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 
 import java.io.PrintWriter;
@@ -106,7 +111,7 @@
 /**
  * Holds the reference to SystemUI.
  */
-public class SystemUiProxy implements ISystemUiProxy {
+public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
     private static final String TAG = SystemUiProxy.class.getSimpleName();
 
     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
@@ -154,7 +159,7 @@
     private IOnBackInvokedCallback mBackToLauncherCallback;
     private IRemoteAnimationRunner mBackToLauncherRunner;
     private IDragAndDrop mDragAndDrop;
-    private IHomeTransitionListener mHomeTransitionListener;
+    private final HomeVisibilityState mHomeVisibilityState = new HomeVisibilityState();
 
     // Used to dedupe calls to SystemUI
     private int mLastShelfHeight;
@@ -177,7 +182,10 @@
      */
     private final PendingIntent mRecentsPendingIntent;
 
-    public SystemUiProxy(Context context) {
+    @Nullable
+    private final ProxyUnfoldTransitionProvider mUnfoldTransitionProvider;
+
+    private SystemUiProxy(Context context) {
         mContext = context;
         mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
         final Intent baseIntent = new Intent().setPackage(mContext.getPackageName());
@@ -187,9 +195,16 @@
         mRecentsPendingIntent = PendingIntent.getActivity(mContext, 0, baseIntent,
                 PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
                         | Intent.FILL_IN_COMPONENT, options.toBundle());
+
+        mUnfoldTransitionProvider =
+                (enableUnfoldStateAnimation() && new ResourceUnfoldTransitionConfig().isEnabled())
+                         ? new ProxyUnfoldTransitionProvider() : null;
     }
 
     @Override
+    public void close() { }
+
+    @Override
     public void onBackPressed() {
         if (mSystemUiProxy != null) {
             try {
@@ -251,7 +266,7 @@
         mRecentTasks = recentTasks;
         mBackAnimation = backAnimation;
         mDesktopMode = desktopMode;
-        mUnfoldAnimation = unfoldAnimation;
+        mUnfoldAnimation = enableUnfoldStateAnimation() ? null : unfoldAnimation;
         mDragAndDrop = dragAndDrop;
         linkToDeath();
         // re-attach the listeners once missing due to setProxy has not been initialized yet.
@@ -259,7 +274,7 @@
         setBubblesListener(mBubblesListener);
         registerSplitScreenListener(mSplitScreenListener);
         registerSplitSelectListener(mSplitSelectListener);
-        setHomeTransitionListener(mHomeTransitionListener);
+        mHomeVisibilityState.init(mShellTransitions);
         setStartingWindowListener(mStartingWindowListener);
         setLauncherUnlockAnimationController(
                 mLauncherActivityClass, mLauncherUnlockAnimationController);
@@ -272,6 +287,19 @@
         setAssistantOverridesRequested(
                 AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
         mStateChangeCallbacks.forEach(Runnable::run);
+
+        if (mUnfoldTransitionProvider != null) {
+            if (unfoldAnimation != null) {
+                try {
+                    unfoldAnimation.setListener(mUnfoldTransitionProvider);
+                    mUnfoldTransitionProvider.setActive(true);
+                } catch (RemoteException e) {
+                    // Ignore
+                }
+            } else {
+                mUnfoldTransitionProvider.setActive(false);
+            }
+        }
     }
 
     /**
@@ -432,6 +460,17 @@
     }
 
     @Override
+    public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call setOverrideHomeButtonLongPress", e);
+            }
+        }
+    }
+
+    @Override
     public void notifyAccessibilityButtonClicked(int displayId) {
         if (mSystemUiProxy != null) {
             try {
@@ -630,10 +669,11 @@
      * should be responsible for cleaning up the overlay.
      */
     public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
-            SurfaceControl overlay) {
+            SurfaceControl overlay, Rect appBounds) {
         if (mPip != null) {
             try {
-                mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
+                mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
+                        appBounds);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call stopSwipePipToHome");
             }
@@ -707,15 +747,12 @@
     /**
      * Tells SysUI to show the bubble with the provided key.
      * @param key the key of the bubble to show.
-     * @param bubbleBarOffsetX the offset of the bubble bar from the edge of the screen on the X
-     *                         axis.
-     * @param bubbleBarOffsetY the offset of the bubble bar from the edge of the screen on the Y
-     *                         axis.
+     * @param bubbleBarBounds bounds of the bubble bar in display coordinates
      */
-    public void showBubble(String key, int bubbleBarOffsetX, int bubbleBarOffsetY) {
+    public void showBubble(String key, Rect bubbleBarBounds) {
         if (mBubbles != null) {
             try {
-                mBubbles.showBubble(key, bubbleBarOffsetX, bubbleBarOffsetY);
+                mBubbles.showBubble(key, bubbleBarBounds);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call showBubble");
             }
@@ -787,6 +824,32 @@
         }
     }
 
+    /**
+     * Tells SysUI to update the bubble bar location to the new location.
+     * @param location new location for the bubble bar
+     */
+    public void setBubbleBarLocation(BubbleBarLocation location) {
+        try {
+            mBubbles.setBubbleBarLocation(location);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call setBubbleBarLocation");
+        }
+    }
+
+    /**
+     * Tells SysUI the bounds for the bubble bar
+     * @param bubbleBarBounds bounds of the bubble bar in display coordinates
+     */
+    public void setBubbleBarBounds(Rect bubbleBarBounds) {
+        try {
+            if (mBubbles != null) {
+                mBubbles.setBubbleBarBounds(bubbleBarBounds);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed call setBubbleBarBounds");
+        }
+    }
+
     //
     // Splitscreen
     //
@@ -1081,22 +1144,8 @@
         mRemoteTransitions.remove(remoteTransition);
     }
 
-    public void setHomeTransitionListener(IHomeTransitionListener listener) {
-        if (!FeatureFlags.enableHomeTransitionListener()) {
-            return;
-        }
-
-        mHomeTransitionListener = listener;
-
-        if (mShellTransitions != null) {
-            try {
-                mShellTransitions.setHomeTransitionListener(listener);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed call setHomeTransitionListener", e);
-            }
-        } else  {
-            Log.w(TAG, "Unable to call setHomeTransitionListener because ShellTransitions is null");
-        }
+    public HomeVisibilityState getHomeVisibilityState() {
+        return mHomeVisibilityState;
     }
 
     /**
@@ -1323,8 +1372,7 @@
      * Gets the set of running tasks.
      */
     public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
-        if (mRecentTasks != null
-                && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
+        if (mRecentTasks != null && shouldEnableRunningTasksForDesktopMode()) {
             try {
                 return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
             } catch (RemoteException e) {
@@ -1334,6 +1382,12 @@
         return new ArrayList<>();
     }
 
+    private boolean shouldEnableRunningTasksForDesktopMode() {
+        // TODO(b/335401172): unify DesktopMode checks in Launcher
+        return (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps())
+                || mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
+    }
+
     private boolean handleMessageAsync(Message msg) {
         switch (msg.what) {
             case MSG_SET_SHELF_HEIGHT:
@@ -1432,6 +1486,17 @@
         }
     }
 
+    /** Call shell to move a task with given `taskId` to desktop  */
+    public void moveToDesktop(int taskId) {
+        if (mDesktopMode != null) {
+            try {
+                mDesktopMode.moveToDesktop(taskId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call moveToDesktop", e);
+            }
+        }
+    }
+
     //
     // Unfold transition
     //
@@ -1450,6 +1515,11 @@
         }
     }
 
+    @Nullable
+    public ProxyUnfoldTransitionProvider getUnfoldTransitionProvider() {
+        return mUnfoldTransitionProvider;
+    }
+
     //
     // Recents
     //
@@ -1532,7 +1602,7 @@
         pw.println("\tmSplitSelectListener=" + mSplitSelectListener);
         pw.println("\tmOneHanded=" + mOneHanded);
         pw.println("\tmShellTransitions=" + mShellTransitions);
-        pw.println("\tmHomeTransitionListener=" + mHomeTransitionListener);
+        pw.println("\tmHomeVisibilityState=" + mHomeVisibilityState);
         pw.println("\tmStartingWindow=" + mStartingWindow);
         pw.println("\tmStartingWindowListener=" + mStartingWindowListener);
         pw.println("\tmSysuiUnlockAnimationController=" + mSysuiUnlockAnimationController);
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 8e03a91..9d899fc 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -17,6 +17,7 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
@@ -38,6 +39,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
@@ -48,6 +50,7 @@
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
+import java.io.PrintWriter;
 import java.util.HashMap;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@@ -56,6 +59,7 @@
     public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
             && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
 
+    private final Context mCtx;
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
     private RecentsAnimationTargets mTargets;
@@ -63,7 +67,9 @@
     private GestureState mLastGestureState;
     private RemoteAnimationTarget[] mLastAppearedTaskTargets;
     private Runnable mLiveTileCleanUpHandler;
-    private Context mCtx;
+
+    private boolean mRecentsAnimationStartPending = false;
+    private boolean mShouldIgnoreMotionEvents = false;
 
     private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
         @Override
@@ -74,10 +80,11 @@
                         mLiveTileRestartListener);
                 return;
             }
-            BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
-            if (activityInterface.isInLiveTileMode()
-                    && activityInterface.getCreatedActivity() != null) {
-                RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
+            BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
+            if (containerInterface.isInLiveTileMode()
+                    && containerInterface.getCreatedContainer() != null) {
+                RecentsView recentsView = containerInterface.getCreatedContainer()
+                        .getOverviewPanel();
                 if (recentsView != null) {
                     recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId);
                     TaskStackChangeListeners.getInstance().unregisterTaskStackListener(
@@ -99,6 +106,18 @@
                 .startRecentsActivity(intent, 0, null, null, null));
     }
 
+    boolean shouldIgnoreMotionEvents() {
+        return mShouldIgnoreMotionEvents;
+    }
+
+    void notifyNewGestureStart() {
+        // If mRecentsAnimationStartPending is true at the beginning of a gesture, block all motion
+        // events for this new gesture so that this new gesture does not interfere with the
+        // previously-requested recents animation. Otherwise, clean up mShouldIgnoreMotionEvents.
+        // NOTE: this can lead to misleading logs
+        mShouldIgnoreMotionEvents = mRecentsAnimationStartPending;
+    }
+
     /**
      * Starts a new recents animation for the activity with the given {@param intent}.
      */
@@ -128,15 +147,21 @@
             cleanUpRecentsAnimation(mCallbacks);
         }
 
-        final BaseActivityInterface activityInterface = gestureState.getActivityInterface();
+        final BaseContainerInterface containerInterface = gestureState.getContainerInterface();
         mLastGestureState = gestureState;
         RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks(
-                SystemUiProxy.INSTANCE.get(mCtx), activityInterface.allowMinimizeSplitScreen());
+                SystemUiProxy.INSTANCE.get(mCtx), containerInterface.allowMinimizeSplitScreen());
         mCallbacks = newCallbacks;
         mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
                     RecentsAnimationTargets targets) {
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation(onRecentsAnimationStart): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 if (mCallbacks == null) {
                     // It's possible for the recents animation to have finished and be cleaned up
                     // by the time we process the start callback, and in that case, just we can skip
@@ -177,28 +202,53 @@
 
             @Override
             public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation")
+                            .append("(onRecentsAnimationCanceled): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 cleanUpRecentsAnimation(newCallbacks);
             }
 
             @Override
             public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+                if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
+                    ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                            "TaskAnimationManager.startRecentsAnimation")
+                            .append("(onRecentsAnimationFinished): ")
+                            .append("Setting mRecentsAnimationStartPending = false"));
+                    mRecentsAnimationStartPending = false;
+                }
                 cleanUpRecentsAnimation(newCallbacks);
             }
 
+            private boolean isNonRecentsStartedTasksAppeared(
+                    RemoteAnimationTarget[] appearedTaskTargets) {
+                // For example, right after swiping from task X to task Y (e.g. from
+                // AbsSwipeUpHandler#startNewTask), and then task Y starts X immediately
+                // (e.g. in Y's onResume). The case will be: lastStartedTask=Y and appearedTask=X.
+                return mLastGestureState.getEndTarget() == GestureState.GestureEndTarget.NEW_TASK
+                        && ArrayUtils.find(appearedTaskTargets,
+                                mLastGestureState.mLastStartedTaskIdPredicate) == null;
+            }
+
             @Override
             public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) {
                 RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0];
-                BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
+                BaseContainerInterface containerInterface =
+                        mLastGestureState.getContainerInterface();
 
                 for (RemoteAnimationTarget compat : appearedTaskTargets) {
                     if (compat.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME
-                            && activityInterface.getCreatedActivity() instanceof RecentsActivity
+                            && containerInterface.getCreatedContainer() instanceof RecentsActivity
                             && DisplayController.getNavigationMode(mCtx) != NO_BUTTON) {
                         // The only time we get onTasksAppeared() in button navigation with a
                         // 3p launcher is if the user goes to overview first, and in this case we
                         // can immediately finish the transition
                         RecentsView recentsView =
-                                activityInterface.getCreatedActivity().getOverviewPanel();
+                                containerInterface.getCreatedContainer().getOverviewPanel();
                         if (recentsView != null) {
                             recentsView.finishRecentsAnimation(true, null);
                         }
@@ -206,16 +256,18 @@
                     }
                 }
 
-                RemoteAnimationTarget[] nonAppTargets = SystemUiProxy.INSTANCE.get(mCtx)
-                        .onStartingSplitLegacy(appearedTaskTargets);
+                RemoteAnimationTarget[] nonAppTargets = ENABLE_SHELL_TRANSITIONS
+                        ? null : SystemUiProxy.INSTANCE.get(mCtx).onStartingSplitLegacy(
+                                appearedTaskTargets);
                 if (nonAppTargets == null) {
                     nonAppTargets = new RemoteAnimationTarget[0];
                 }
-                if ((activityInterface.isInLiveTileMode()
-                            || mLastGestureState.getEndTarget() == RECENTS)
-                        && activityInterface.getCreatedActivity() != null) {
+                if ((containerInterface.isInLiveTileMode()
+                            || mLastGestureState.getEndTarget() == RECENTS
+                            || isNonRecentsStartedTasksAppeared(appearedTaskTargets))
+                        && containerInterface.getCreatedContainer() != null) {
                     RecentsView recentsView =
-                            activityInterface.getCreatedActivity().getOverviewPanel();
+                            containerInterface.getCreatedContainer().getOverviewPanel();
                     if (recentsView != null) {
                         ActiveGestureLog.INSTANCE.addLog(
                                 new ActiveGestureLog.CompoundString("Launching side task id=")
@@ -250,13 +302,13 @@
 
             @Override
             public boolean onSwitchToScreenshot(Runnable onFinished) {
-                if (!activityInterface.isInLiveTileMode()
-                        || activityInterface.getCreatedActivity() == null) {
+                if (!containerInterface.isInLiveTileMode()
+                        || containerInterface.getCreatedContainer() == null) {
                     // No need to switch since tile is already a screenshot.
                     onFinished.run();
                 } else {
                     final RecentsView recentsView =
-                            activityInterface.getCreatedActivity().getOverviewPanel();
+                            containerInterface.getCreatedContainer().getOverviewPanel();
                     if (recentsView != null) {
                         recentsView.switchToScreenshot(onFinished);
                     } else {
@@ -273,14 +325,36 @@
         if (ENABLE_SHELL_TRANSITIONS) {
             final ActivityOptions options = ActivityOptions.makeBasic();
             // Use regular (non-transient) launch for all apps page to control IME.
-            if (!activityInterface.allowAllAppsFromOverview()) {
+            if (!containerInterface.allowAllAppsFromOverview()) {
                 options.setTransientLaunch();
             }
             options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
-            SystemUiProxy.INSTANCE.getNoCreate().startRecentsActivity(intent, options, mCallbacks);
+            mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx)
+                    .startRecentsActivity(intent, options, mCallbacks);
+            if (enableHandleDelayedGestureCallbacks()) {
+                ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
+                        "TaskAnimationManager.startRecentsAnimation(shell transition path): ")
+                        .append("Setting mRecentsAnimationStartPending = ")
+                        .append(mRecentsAnimationStartPending));
+            }
         } else {
-            UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
-                    .startRecentsActivity(intent, eventTime, mCallbacks, null, null));
+            UI_HELPER_EXECUTOR.execute(
+                    () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
+                            intent,
+                            eventTime,
+                            mCallbacks,
+                            result -> {
+                                if (enableHandleDelayedGestureCallbacks()) {
+                                    ActiveGestureLog.INSTANCE.addLog(
+                                            new ActiveGestureLog.CompoundString(
+                                                    "TaskAnimationManager.startRecentsAnimation")
+                                                    .append("(legacy path): Setting ")
+                                                    .append("mRecentsAnimationStartPending = ")
+                                                    .append(result));
+                                }
+                                mRecentsAnimationStartPending = result;
+                            },
+                            MAIN_EXECUTOR.getHandler()));
         }
         gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED);
         return mCallbacks;
@@ -304,10 +378,10 @@
         if (mLastGestureState == null) {
             return;
         }
-        BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
-        if (activityInterface.isInLiveTileMode()
-                && activityInterface.getCreatedActivity() != null) {
-            RecentsView recentsView = activityInterface.getCreatedActivity().getOverviewPanel();
+        BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
+        if (containerInterface.isInLiveTileMode()
+                && containerInterface.getCreatedContainer() != null) {
+            RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel();
             if (recentsView != null) {
                 recentsView.switchToScreenshot(null,
                         () -> recentsView.finishRecentsAnimation(true /* toRecents */,
@@ -409,7 +483,24 @@
         return mCallbacks;
     }
 
-    public void dump() {
-        // TODO
+    public void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "TaskAnimationManager:");
+
+        if (enableHandleDelayedGestureCallbacks()) {
+            pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending);
+            pw.println(prefix + "\tmShouldIgnoreUpcomingGestures=" + mShouldIgnoreMotionEvents);
+        }
+        if (mController != null) {
+            mController.dump(prefix + '\t', pw);
+        }
+        if (mCallbacks != null) {
+            mCallbacks.dump(prefix + '\t', pw);
+        }
+        if (mTargets != null) {
+            mTargets.dump(prefix + '\t', pw);
+        }
+        if (mLastGestureState != null) {
+            mLastGestureState.dump(prefix + '\t', pw);
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 1b3f598..e6febff 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -41,12 +42,12 @@
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.Preconditions;
-import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.TaskKeyLruCache;
 import com.android.quickstep.util.TaskVisualsChangeListener;
 import com.android.systemui.shared.recents.model.Task;
@@ -109,21 +110,17 @@
             callback.accept(task);
             return null;
         }
-        CancellableTask<TaskCacheEntry> request = new CancellableTask<TaskCacheEntry>() {
-            @Override
-            public TaskCacheEntry getResultOnBg() {
-                return getCacheEntry(task);
-            }
-
-            @Override
-            public void handleResult(TaskCacheEntry result) {
-                task.icon = result.icon;
-                task.titleDescription = result.contentDescription;
-                task.title = result.title;
-                callback.accept(task);
-                dispatchIconUpdate(task.key.id);
-            }
-        };
+        CancellableTask<TaskCacheEntry> request = new CancellableTask<>(
+                () -> getCacheEntry(task),
+                MAIN_EXECUTOR,
+                result -> {
+                    task.icon = result.icon;
+                    task.titleDescription = result.contentDescription;
+                    task.title = result.title;
+                    callback.accept(task);
+                    dispatchIconUpdate(task.key.id);
+                }
+        );
         mBgExecutor.execute(request);
         return request;
     }
@@ -191,8 +188,7 @@
             entry.contentDescription = getBadgedContentDescription(
                     activityInfo, task.key.userId, task.taskDescription);
             if (enableOverviewIconMenu()) {
-                entry.title = Utilities.trim(
-                        activityInfo.applicationInfo.loadLabel(mContext.getPackageManager()));
+                entry.title = Utilities.trim(activityInfo.loadLabel(mContext.getPackageManager()));
             }
         }
 
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index 312cdc9..18b8e3e 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -33,7 +33,6 @@
 import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.ItemInfo;
@@ -43,8 +42,10 @@
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.Snackbar;
 import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -62,14 +63,15 @@
     public static List<SystemShortcut> getEnabledShortcuts(TaskView taskView,
             TaskIdAttributeContainer taskContainer) {
         final ArrayList<SystemShortcut> shortcuts = new ArrayList<>();
-        final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext());
+        final RecentsViewContainer container =
+                RecentsViewContainer.containerFromContext(taskView.getContext());
         boolean hasMultipleTasks = taskView.getTaskIds()[1] != -1;
         for (TaskShortcutFactory menuOption : MENU_OPTIONS) {
             if (hasMultipleTasks && !menuOption.showForSplitscreen()) {
                 continue;
             }
 
-            List<SystemShortcut> menuShortcuts = menuOption.getShortcuts(activity, taskContainer);
+            List<SystemShortcut> menuShortcuts = menuOption.getShortcuts(container, taskContainer);
             if (menuShortcuts == null) {
                 continue;
             }
@@ -78,15 +80,16 @@
         RecentsOrientedState orientedState = taskView.getRecentsView().getPagedViewOrientedState();
         boolean canLauncherRotate = orientedState.isRecentsActivityRotationAllowed();
         boolean isInLandscape = orientedState.getTouchRotation() != ROTATION_0;
-        boolean isTablet = activity.getDeviceProfile().isTablet;
+        boolean isTablet = container.getDeviceProfile().isTablet;
 
         boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
-        // Add overview actions to the menu when in in-place rotate landscape mode, or in
-        // grid-only overview.
-        if ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview) {
+        // Add overview actions to the menu when:
+        // - single task is showing
+        // - in in-place rotate landscape mode, or in grid-only overview.
+        if (!hasMultipleTasks && ((!canLauncherRotate && isInLandscape) || isGridOnlyOverview)) {
             // Add screenshot action to task menu.
             List<SystemShortcut> screenshotShortcuts = TaskShortcutFactory.SCREENSHOT
-                    .getShortcuts(activity, taskContainer);
+                    .getShortcuts(container, taskContainer);
             if (screenshotShortcuts != null) {
                 shortcuts.addAll(screenshotShortcuts);
             }
@@ -95,7 +98,7 @@
             // or in grid-only overview.
             if (orientedState.getDisplayRotation() == ROTATION_0 || isGridOnlyOverview) {
                 List<SystemShortcut> modalShortcuts = TaskShortcutFactory.MODAL
-                        .getShortcuts(activity, taskContainer);
+                        .getShortcuts(container, taskContainer);
                 if (modalShortcuts != null) {
                     shortcuts.addAll(modalShortcuts);
                 }
@@ -135,6 +138,7 @@
             TaskShortcutFactory.PIN,
             TaskShortcutFactory.INSTALL,
             TaskShortcutFactory.FREE_FORM,
+            DesktopSystemShortcut.Companion.createFactory(),
             TaskShortcutFactory.WELLBEING,
             TaskShortcutFactory.SAVE_APP_PAIR
     };
@@ -210,13 +214,19 @@
             }
         }
 
-        private void enterSplitSelect() {
+        protected void enterSplitSelect() {
             RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView();
             // Task has already been dismissed
             if (overviewPanel == null) return;
             overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView());
         }
 
+        protected void saveAppPair() {
+            GroupedTaskView taskView = (GroupedTaskView) mThumbnailView.getTaskView();
+            taskView.getRecentsView().getSplitSelectController().getAppPairsController()
+                    .saveAppPair(taskView);
+        }
+
         /**
          * Called when the overlay is no longer used.
          */
@@ -246,9 +256,9 @@
         /**
          * Gets the system shortcut for the screenshot that will be added to the task menu.
          */
-        public SystemShortcut getScreenshotShortcut(BaseDraggingActivity activity,
+        public SystemShortcut getScreenshotShortcut(RecentsViewContainer container,
                 ItemInfo iteminfo, View originalView) {
-            return new ScreenshotSystemShortcut(activity, iteminfo, originalView);
+            return new ScreenshotSystemShortcut(container, iteminfo, originalView);
         }
 
         /**
@@ -296,19 +306,19 @@
 
         private class ScreenshotSystemShortcut extends SystemShortcut {
 
-            private final BaseDraggingActivity mActivity;
+            private final RecentsViewContainer mContainer;
 
-            ScreenshotSystemShortcut(BaseDraggingActivity activity, ItemInfo itemInfo,
+            ScreenshotSystemShortcut(RecentsViewContainer container, ItemInfo itemInfo,
                     View originalView) {
-                super(R.drawable.ic_screenshot, R.string.action_screenshot, activity, itemInfo,
+                super(R.drawable.ic_screenshot, R.string.action_screenshot, container, itemInfo,
                         originalView);
-                mActivity = activity;
+                mContainer = container;
             }
 
             @Override
             public void onClick(View view) {
                 saveScreenshot(mThumbnailView.getTaskView().getTask());
-                dismissTaskMenuView(mActivity);
+                dismissTaskMenuView();
             }
         }
 
@@ -329,6 +339,10 @@
             public void onSplit() {
                 endLiveTileMode(TaskOverlay.this::enterSplitSelect);
             }
+
+            public void onSaveAppPair() {
+                endLiveTileMode(TaskOverlay.this::saveAppPair);
+            }
         }
     }
 
@@ -342,5 +356,8 @@
 
         /** User wants to start split screen with current app. */
         void onSplit();
+
+        /** User wants to save an app pair with current group of apps. */
+        void onSaveAppPair();
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 73b786f..9d10ac1 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -20,9 +20,8 @@
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 
-import android.app.Activity;
 import android.app.ActivityOptions;
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -39,19 +38,21 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
 import com.android.launcher3.model.WellbeingModel;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.popup.SystemShortcut.AppInfo;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -61,6 +62,7 @@
 import com.android.systemui.shared.recents.view.RecentsTransition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.function.Function;
@@ -72,7 +74,7 @@
  */
 public interface TaskShortcutFactory {
     @Nullable
-    default List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+    default List<SystemShortcut> getShortcuts(RecentsViewContainer container,
             TaskIdAttributeContainer taskContainer) {
         return null;
     }
@@ -92,7 +94,7 @@
 
     TaskShortcutFactory APP_INFO = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
             TaskView taskView = taskContainer.getTaskView();
             AppInfo.SplitAccessibilityInfo accessibilityInfo =
@@ -100,7 +102,7 @@
                             TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()),
                             taskContainer.getA11yNodeId()
                     );
-            return Collections.singletonList(new AppInfo(activity, taskContainer.getItemInfo(),
+            return Collections.singletonList(new AppInfo(container, taskContainer.getItemInfo(),
                     taskView, accessibilityInfo));
         }
 
@@ -114,9 +116,9 @@
         private final TaskView mTaskView;
         private final SplitPositionOption mSplitPositionOption;
 
-        public SplitSelectSystemShortcut(BaseDraggingActivity target, TaskView taskView,
+        public SplitSelectSystemShortcut(RecentsViewContainer container, TaskView taskView,
                 SplitPositionOption option) {
-            super(option.iconResId, option.textResId, target, taskView.getItemInfo(), taskView);
+            super(option.iconResId, option.textResId, container, taskView.getItemInfo(), taskView);
             mTaskView = taskView;
             mSplitPositionOption = option;
         }
@@ -131,24 +133,26 @@
      * A menu item, "Save app pair", that allows the user to preserve the current app combination as
      * one persistent icon on the Home screen, allowing for quick split screen launching.
      */
-    class SaveAppPairSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
+    class SaveAppPairSystemShortcut extends SystemShortcut<RecentsViewContainer> {
         private final GroupedTaskView mTaskView;
 
-        public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView) {
-            super(R.drawable.ic_save_app_pair, R.string.save_app_pair, activity,
+
+        public SaveAppPairSystemShortcut(RecentsViewContainer container, GroupedTaskView taskView,
+            int iconResId) {
+                super(iconResId, R.string.save_app_pair, container,
                     taskView.getItemInfo(), taskView);
             mTaskView = taskView;
         }
 
         @Override
         public void onClick(View view) {
-            dismissTaskMenuView(mTarget);
+            dismissTaskMenuView();
             ((RecentsView) mTarget.getOverviewPanel())
                     .getSplitSelectController().getAppPairsController().saveAppPair(mTaskView);
         }
     }
 
-    class FreeformSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
+    class FreeformSystemShortcut extends SystemShortcut<RecentsViewContainer> {
         private static final String TAG = "FreeformSystemShortcut";
 
         private Handler mHandler;
@@ -158,20 +162,20 @@
         private final TaskView mTaskView;
         private final LauncherEvent mLauncherEvent;
 
-        public FreeformSystemShortcut(int iconRes, int textRes, BaseDraggingActivity activity,
+        public FreeformSystemShortcut(int iconRes, int textRes, RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer, LauncherEvent launcherEvent) {
-            super(iconRes, textRes, activity, taskContainer.getItemInfo(),
+            super(iconRes, textRes, container, taskContainer.getItemInfo(),
                     taskContainer.getTaskView());
             mLauncherEvent = launcherEvent;
             mHandler = new Handler(Looper.getMainLooper());
             mTaskView = taskContainer.getTaskView();
-            mRecentsView = activity.getOverviewPanel();
+            mRecentsView = container.getOverviewPanel();
             mThumbnailView = taskContainer.getThumbnailView();
         }
 
         @Override
         public void onClick(View view) {
-            dismissTaskMenuView(mTarget);
+            dismissTaskMenuView();
             RecentsView rv = mTarget.getOverviewPanel();
             rv.switchToScreenshot(() -> {
                 rv.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */, () -> {
@@ -249,11 +253,11 @@
             }
         }
 
-        private ActivityOptions makeLaunchOptions(Activity activity) {
+        private ActivityOptions makeLaunchOptions(RecentsViewContainer container) {
             ActivityOptions activityOptions = ActivityOptions.makeBasic();
             activityOptions.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
             // Arbitrary bounds only because freeform is in dev mode right now
-            final View decorView = activity.getWindow().getDecorView();
+            final View decorView = container.getWindow().getDecorView();
             final WindowInsets insets = decorView.getRootWindowInsets();
             final Rect r = new Rect(0, 0, decorView.getWidth() / 2, decorView.getHeight() / 2);
             r.offsetTo(insets.getSystemWindowInsetLeft() + 50,
@@ -274,21 +278,21 @@
      */
     TaskShortcutFactory SPLIT_SELECT = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
-            DeviceProfile deviceProfile = activity.getDeviceProfile();
+            DeviceProfile deviceProfile = container.getDeviceProfile();
             final Task task = taskContainer.getTask();
             final int intentFlags = task.key.baseIntent.getFlags();
             final TaskView taskView = taskContainer.getTaskView();
             final RecentsView recentsView = taskView.getRecentsView();
-            final PagedOrientationHandler orientationHandler =
+            final RecentsPagedOrientationHandler orientationHandler =
                     recentsView.getPagedOrientationHandler();
 
             boolean notEnoughTasksToSplit =
                     !deviceProfile.isTaskbarPresent && recentsView.getTaskViewCount() < 2;
             boolean isTaskSplitNotSupported = !task.isDockable ||
                     (intentFlags & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) != 0;
-            boolean hideForExistingMultiWindow = activity.getDeviceProfile().isMultiWindowMode;
+            boolean hideForExistingMultiWindow = container.getDeviceProfile().isMultiWindowMode;
             boolean isFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
             boolean isTaskInExpectedScrollPosition =
                     recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
@@ -301,7 +305,7 @@
             return orientationHandler.getSplitPositionOptions(deviceProfile)
                     .stream()
                     .map((Function<SplitPositionOption, SystemShortcut>) option ->
-                            new SplitSelectSystemShortcut(activity, taskView, option))
+                            new SplitSelectSystemShortcut(container, taskView, option))
                     .collect(Collectors.toList());
         }
     };
@@ -309,16 +313,44 @@
     TaskShortcutFactory SAVE_APP_PAIR = new TaskShortcutFactory() {
         @Nullable
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
+            DeviceProfile deviceProfile = container.getDeviceProfile();
             final TaskView taskView = taskContainer.getTaskView();
+            final RecentsView recentsView = taskView.getRecentsView();
+            boolean isLargeTileFocusedTask = deviceProfile.isTablet && taskView.isFocusedTask();
+            boolean isInExpectedScrollPosition =
+                    recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
+            boolean shouldShowActionsButtonInstead =
+                    isLargeTileFocusedTask && isInExpectedScrollPosition;
+            boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskIdAttributeContainers())
+                    .anyMatch(att -> att != null && att.getItemInfo() != null
+                            && ((att.getItemInfo().runtimeStatusFlags
+                                & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
 
-            if (!FeatureFlags.enableAppPairs() || !taskView.containsMultipleTasks()) {
+            // No "save app pair" menu item if:
+            // - app pairs feature is not enabled
+            // - we are in 3p launcher
+            // - the task in question is a single task
+            // - at least one app in app pair is unpinnable
+            // - the Overview Actions Button should be visible
+            // - the task is not a GroupedTaskView
+            if (!FeatureFlags.enableAppPairs()
+                    || !recentsView.supportsAppPairs()
+                    || !taskView.containsMultipleTasks()
+                    || hasUnpinnableApp
+                    || shouldShowActionsButtonInstead
+                    || !(taskView instanceof GroupedTaskView)) {
                 return null;
             }
 
+            int iconResId = deviceProfile.isLeftRightSplit
+                    ? R.drawable.ic_save_app_pair_left_right
+                    : R.drawable.ic_save_app_pair_up_down;
+
             return Collections.singletonList(
-                    new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView));
+                    new SaveAppPairSystemShortcut(container,
+                            (GroupedTaskView) taskView, iconResId));
         }
 
         @Override
@@ -329,35 +361,35 @@
 
     TaskShortcutFactory FREE_FORM = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
             final Task task = taskContainer.getTask();
             if (!task.isDockable) {
                 return null;
             }
-            if (!isAvailable(activity, task.key.displayId)) {
+            if (!isAvailable(container)) {
                 return null;
             }
 
             return Collections.singletonList(new FreeformSystemShortcut(
                     R.drawable.ic_caption_desktop_button_foreground,
-                    R.string.recent_task_option_freeform, activity, taskContainer,
+                    R.string.recent_task_option_freeform, container, taskContainer,
                     LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP));
         }
 
-        private boolean isAvailable(BaseDraggingActivity activity, int displayId) {
+        private boolean isAvailable(RecentsViewContainer container) {
             return Settings.Global.getInt(
-                    activity.getContentResolver(),
+                    container.asContext().getContentResolver(),
                     Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0
-                    && !isDesktopModeSupported();
+                    && !enableDesktopWindowingMode();
         }
     };
 
     TaskShortcutFactory PIN = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
-            if (!SystemUiProxy.INSTANCE.get(activity).isActive()) {
+            if (!SystemUiProxy.INSTANCE.get(container.asContext()).isActive()) {
                 return null;
             }
             if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) {
@@ -367,17 +399,17 @@
                 // We shouldn't be able to pin while an app is locked.
                 return null;
             }
-            return Collections.singletonList(new PinSystemShortcut(activity, taskContainer));
+            return Collections.singletonList(new PinSystemShortcut(container, taskContainer));
         }
     };
 
-    class PinSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
+    class PinSystemShortcut extends SystemShortcut<RecentsViewContainer> {
 
         private static final String TAG = "PinSystemShortcut";
 
         private final TaskView mTaskView;
 
-        public PinSystemShortcut(BaseDraggingActivity target,
+        public PinSystemShortcut(RecentsViewContainer target,
                 TaskIdAttributeContainer taskContainer) {
             super(R.drawable.ic_pin, R.string.recent_task_option_pin, target,
                     taskContainer.getItemInfo(), taskContainer.getTaskView());
@@ -387,10 +419,10 @@
         @Override
         public void onClick(View view) {
             if (mTaskView.launchTaskAnimated() != null) {
-                SystemUiProxy.INSTANCE.get(mTarget).startScreenPinning(
+                SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning(
                         mTaskView.getTask().key.id);
             }
-            dismissTaskMenuView(mTarget);
+            dismissTaskMenuView();
             mTarget.getStatsLogManager().logger().withItemInfo(mTaskView.getItemInfo())
                     .log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP);
         }
@@ -398,12 +430,12 @@
 
     TaskShortcutFactory INSTALL = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
             Task t = taskContainer.getTask();
-            return InstantAppResolver.newInstance(activity).isInstantApp(
+            return InstantAppResolver.newInstance(container.asContext()).isInstantApp(
                     t.getTopComponent().getPackageName(), t.getKey().userId)
-                    ? Collections.singletonList(new SystemShortcut.Install(activity,
+                    ? Collections.singletonList(new SystemShortcut.Install(container,
                     taskContainer.getItemInfo(), taskContainer.getTaskView()))
                     : null;
         }
@@ -411,10 +443,10 @@
 
     TaskShortcutFactory WELLBEING = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
-            SystemShortcut<BaseDraggingActivity> wellbeingShortcut =
-                    WellbeingModel.SHORTCUT_FACTORY.getShortcut(activity,
+            SystemShortcut<ActivityContext> wellbeingShortcut =
+                    WellbeingModel.SHORTCUT_FACTORY.getShortcut(container,
                             taskContainer.getItemInfo(), taskContainer.getTaskView());
             return createSingletonShortcutList(wellbeingShortcut);
         }
@@ -422,11 +454,11 @@
 
     TaskShortcutFactory SCREENSHOT = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
             SystemShortcut screenshotShortcut =
                     taskContainer.getThumbnailView().getTaskOverlay()
-                            .getScreenshotShortcut(activity, taskContainer.getItemInfo(),
+                            .getScreenshotShortcut(container, taskContainer.getItemInfo(),
                                     taskContainer.getTaskView());
             return createSingletonShortcutList(screenshotShortcut);
         }
@@ -434,7 +466,7 @@
 
     TaskShortcutFactory MODAL = new TaskShortcutFactory() {
         @Override
-        public List<SystemShortcut> getShortcuts(BaseDraggingActivity activity,
+        public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
                 TaskIdAttributeContainer taskContainer) {
             SystemShortcut modalStateSystemShortcut =
                     taskContainer.getThumbnailView().getTaskOverlay()
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 9e21595..b7cbb47 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -16,6 +16,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -23,8 +24,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.R;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.Preconditions;
-import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
 import com.android.quickstep.util.TaskKeyCache;
 import com.android.quickstep.util.TaskKeyLruCache;
@@ -195,33 +196,29 @@
             return null;
         }
 
-        CancellableTask<ThumbnailData> request = new CancellableTask<>() {
-            @Override
-            public ThumbnailData getResultOnBg() {
-                ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail(
-                        key.id, lowResolution);
-                if (thumbnailData.thumbnail != null) {
-                    return thumbnailData;
-                }
-                return ActivityManagerWrapper.getInstance().takeTaskThumbnail(key.id);
-            }
-
-            @Override
-            public void handleResult(ThumbnailData result) {
-                // Avoid an async timing issue that a low res entry replaces an existing high res
-                // entry in high res enabled state, so we check before putting it to cache
-                if (enableGridOnlyOverview() && result.reducedResolution
-                        && getHighResLoadingState().isEnabled()) {
-                    ThumbnailData cachedThumbnail = mCache.getAndInvalidateIfModified(key);
-                    if (cachedThumbnail != null && cachedThumbnail.thumbnail != null
-                            && !cachedThumbnail.reducedResolution) {
-                        return;
+        CancellableTask<ThumbnailData> request = new CancellableTask<>(
+                () -> {
+                    ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance()
+                            .getTaskThumbnail(key.id, lowResolution);
+                    return thumbnailData.thumbnail != null ? thumbnailData
+                            : ActivityManagerWrapper.getInstance().takeTaskThumbnail(key.id);
+                },
+                MAIN_EXECUTOR,
+                result -> {
+                    // Avoid an async timing issue that a low res entry replaces an existing high
+                    // res entry in high res enabled state, so we check before putting it to cache
+                    if (enableGridOnlyOverview() && result.reducedResolution
+                            && getHighResLoadingState().isEnabled()) {
+                        ThumbnailData newCachedThumbnail = mCache.getAndInvalidateIfModified(key);
+                        if (newCachedThumbnail != null && newCachedThumbnail.thumbnail != null
+                                && !newCachedThumbnail.reducedResolution) {
+                            return;
+                        }
                     }
+                    mCache.put(key, result);
+                    callback.accept(result);
                 }
-                mCache.put(key, result);
-                callback.accept(result);
-            }
-        };
+        );
         mBgExecutor.execute(request);
         return request;
     }
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 80a449b..63e536a 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -70,7 +70,7 @@
             return "";
         }
         UserHandle user = UserHandle.of(userId);
-        ApplicationInfo applicationInfo = new PackageManagerHelper(context)
+        ApplicationInfo applicationInfo = PackageManagerHelper.INSTANCE.get(context)
                 .getApplicationInfo(packageName, user, 0);
         if (applicationInfo == null) {
             Log.e(TAG, "Failed to get title for userId=" + userId + ", packageName=" + packageName);
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 11c5ab4..450e960 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -37,20 +37,18 @@
 import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.quickstep.util.AnimUtils.clampToDuration;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Matrix;
 import android.graphics.Matrix.ScaleToFit;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.view.View;
@@ -60,6 +58,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.app.animation.Interpolators;
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.anim.AnimatedFloat;
@@ -69,6 +68,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
 import com.android.quickstep.util.MultiValueUpdateListener;
@@ -82,9 +82,9 @@
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskThumbnailView;
 import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -93,7 +93,6 @@
 /**
  * Utility class for helpful methods related to {@link TaskView} objects and their tasks.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public final class TaskViewUtils {
 
     private TaskViewUtils() {}
@@ -183,7 +182,7 @@
             // Re-use existing handles
             remoteTargetHandles = recentsViewHandles;
         } else {
-            boolean forDesktop = isDesktopModeSupported() && v instanceof DesktopTaskView;
+            boolean forDesktop = v instanceof DesktopTaskView;
             RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
                     recentsView.getSizeStrategy(), targets, forDesktop);
             if (forDesktop) {
@@ -195,12 +194,13 @@
                 remoteTargetHandles = gluer.assignTargets(targets);
             }
         }
+
         final int recentsActivityRotation =
                 recentsView.getPagedViewOrientedState().getRecentsActivityRotation();
-        for (RemoteTargetHandle remoteTargetGluer : remoteTargetHandles) {
-            remoteTargetGluer.getTaskViewSimulator().getOrientationState().setRecentsRotation(
-                    recentsActivityRotation);
-            remoteTargetGluer.getTransformParams().setSyncTransactionApplier(applier);
+        for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
+            remoteTargetHandle.getTaskViewSimulator().getOrientationState()
+                    .setRecentsRotation(recentsActivityRotation);
+            remoteTargetHandle.getTransformParams().setSyncTransactionApplier(applier);
         }
 
         int taskIndex = recentsView.indexOfChild(v);
@@ -208,7 +208,8 @@
         BaseActivity baseActivity = BaseActivity.fromContext(context);
         DeviceProfile dp = baseActivity.getDeviceProfile();
         boolean showAsGrid = dp.isTablet;
-        boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
+        boolean parallaxCenterAndAdjacentTask =
+                !showAsGrid && taskIndex != recentsView.getCurrentPage();
         int taskRectTranslationPrimary = recentsView.getScrollOffset(taskIndex);
         int taskRectTranslationSecondary = showAsGrid ? (int) v.getGridTranslationY() : 0;
 
@@ -266,10 +267,16 @@
             if (navBarTarget != null) {
                 final Rect cropRect = new Rect();
                 out.addOnFrameListener(new MultiValueUpdateListener() {
-                    FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0,
-                            ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR);
-                    FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
-                            ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
+                    FloatProp mNavFadeOut = new FloatProp(1f, 0f, clampToDuration(
+                            NAV_FADE_OUT_INTERPOLATOR,
+                            0,
+                            ANIMATION_NAV_FADE_OUT_DURATION,
+                            out.getDuration()));
+                    FloatProp mNavFadeIn = new FloatProp(0f, 1f, clampToDuration(
+                            NAV_FADE_IN_INTERPOLATOR,
+                            ANIMATION_DELAY_NAV_FADE_IN,
+                            ANIMATION_NAV_FADE_IN_DURATION,
+                            out.getDuration()));
 
                     @Override
                     public void onUpdate(float percent, boolean initOnly) {
@@ -393,10 +400,16 @@
 
         out.addListener(new AnimationSuccessListener() {
             @Override
+            public void onAnimationStart(Animator animation) {
+                for (RemoteTargetHandle remoteTargetHandle : remoteTargetHandles) {
+                    remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
+                }
+            }
+
+            @Override
             public void onAnimationSuccess(Animator animator) {
                 if (isQuickSwitch) {
-                    InteractionJankMonitorWrapper.end(
-                            InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+                    InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
                 }
             }
 
@@ -638,9 +651,36 @@
                         recentsView.post(() -> {
                             stateManager.moveToRestState();
                             stateManager.reapplyState();
+
+                            // We may have notified launcher is not visible so that taskbar can
+                            // stash immediately. Now that the animation is over, we can update
+                            // that launcher is still visible.
+                            TaskbarUIController controller = recentsView.getSizeStrategy()
+                                    .getTaskbarController();
+                            if (controller != null) {
+                                boolean launcherVisible = true;
+                                for (RemoteAnimationTarget target : appTargets) {
+                                    launcherVisible &= target.isTranslucent;
+                                }
+                                if (launcherVisible) {
+                                    controller.onLauncherVisibilityChanged(true);
+                                }
+                            }
                         });
                     });
                 }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    super.onAnimationCancel(animation);
+                    recentsView.onTaskLaunchedInLiveTileModeCancelled();
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    recentsView.setTaskLaunchCancelledRunnable(null);
+                }
             };
         } else {
             AnimatorPlaybackController controller =
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index a2a6dde..3a6b804 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -34,6 +34,7 @@
 import androidx.annotation.UiThread;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitStageInfo;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -57,7 +58,8 @@
  * This class tracked the top-most task and  some 'approximate' task history to allow faster
  * system state estimation during touch interaction
  */
-public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
+public class TopTaskTracker extends ISplitScreenListener.Stub
+        implements TaskStackChangeListener, SafeCloseable {
 
     public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
             new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -67,12 +69,13 @@
     // Ordered list with first item being the most recent task.
     private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
 
-
+    private final Context mContext;
     private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
     private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
     private int mPinnedTaskId = INVALID_TASK_ID;
 
     private TopTaskTracker(Context context) {
+        mContext = context;
         mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
         mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
 
@@ -81,6 +84,12 @@
     }
 
     @Override
+    public void close() {
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
+        SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
+    }
+
+    @Override
     public void onTaskRemoved(int taskId) {
         mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index eb4591d..a842b51 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -23,12 +23,16 @@
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
 
+import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks;
+import static com.android.launcher3.Flags.useActivityOverlay;
 import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE;
 import static com.android.launcher3.LauncherPrefs.backedUpItem;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
 import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
 import static com.android.quickstep.GestureState.DEFAULT_STATE;
@@ -38,12 +42,14 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
+import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENTS_ANIMATION_START_PENDING;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
@@ -55,17 +61,13 @@
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
 
-import android.annotation.TargetApi;
 import android.app.PendingIntent;
-import android.app.RemoteAction;
 import android.app.Service;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Region;
-import android.graphics.drawable.Icon;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
@@ -76,8 +78,6 @@
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.MotionEvent;
-import android.view.SurfaceControl;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
@@ -86,10 +86,8 @@
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.ConstantItem;
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.EncryptionType;
 import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.provider.RestoreDbTask;
@@ -99,11 +97,9 @@
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.uioverrides.flags.FlagsFactory;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LockedUserState;
+import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.ScreenOnTracker;
 import com.android.launcher3.util.TraceHelper;
@@ -125,6 +121,7 @@
 import com.android.quickstep.util.ActiveGestureLog.CompoundString;
 import com.android.quickstep.util.AssistStateManager;
 import com.android.quickstep.util.AssistUtils;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -135,14 +132,14 @@
 import com.android.systemui.unfold.progress.IUnfoldAnimation;
 import com.android.wm.shell.back.IBackAnimation;
 import com.android.wm.shell.bubbles.IBubbles;
+import com.android.wm.shell.common.pip.IPip;
 import com.android.wm.shell.desktopmode.IDesktopMode;
 import com.android.wm.shell.draganddrop.IDragAndDrop;
 import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.pip.IPip;
 import com.android.wm.shell.recents.IRecentTasks;
+import com.android.wm.shell.shared.IShellTransitions;
 import com.android.wm.shell.splitscreen.ISplitScreen;
 import com.android.wm.shell.startingsurface.IStartingWindow;
-import com.android.wm.shell.transition.IShellTransitions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -153,7 +150,6 @@
 /**
  * Service connected by system-UI for handling touch interaction.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class TouchInteractionService extends Service {
 
     private static final String SUBSTRING_PREFIX = "; ";
@@ -303,15 +299,6 @@
             });
         }
 
-        @Override
-        public void onNavigationBarSurface(SurfaceControl surface) {
-            // TODO: implement
-            if (surface != null) {
-                surface.release();
-                surface = null;
-            }
-        }
-
         @BinderThread
         public void onSystemUiStateChanged(int stateFlags) {
             MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> {
@@ -332,7 +319,7 @@
         public void enterStageSplitFromRunningApp(boolean leftOrTop) {
             executeForTouchInteractionService(tis -> {
                 StatefulActivity activity =
-                        tis.mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
+                        tis.mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
                 if (activity != null) {
                     activity.enterStageSplitFromRunningApp(leftOrTop);
                 }
@@ -373,6 +360,12 @@
                     taskbarManager.onNavButtonsDarkIntensityChanged(darkIntensity));
         }
 
+        @Override
+        public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
+            executeForTaskbarManager(taskbarManager ->
+                    taskbarManager.onNavigationBarLumaSamplingEnabled(displayId, enable));
+        }
+
         private void executeForTouchInteractionService(
                 @NonNull Consumer<TouchInteractionService> tisConsumer) {
             TouchInteractionService tis = mTis.get();
@@ -402,6 +395,14 @@
         }
 
         /**
+         * Sets whether a predictive back-to-home animation is in progress in the device state
+         */
+        public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
+            executeForTouchInteractionService(tis ->
+                    tis.mDeviceState.setPredictiveBackToHomeInProgress(isInProgress));
+        }
+
+        /**
          * Returns the {@link OverviewCommandHelper}.
          * <p>
          * Returns {@code null} if TouchInteractionService is not connected
@@ -443,8 +444,10 @@
 
         /** Refreshes the current overview target. */
         public void refreshOverviewTarget() {
-            executeForTouchInteractionService(tis -> tis.onOverviewTargetChange(
-                    tis.mOverviewComponentObserver.isHomeAndOverviewSame()));
+            executeForTouchInteractionService(tis -> {
+                tis.mAllAppsActionManager.onDestroy();
+                tis.onOverviewTargetChange(tis.mOverviewComponentObserver.isHomeAndOverviewSame());
+            });
         }
     }
 
@@ -485,6 +488,7 @@
 
     private TaskbarManager mTaskbarManager;
     private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
+    private AllAppsActionManager mAllAppsActionManager;
 
     @Override
     public void onCreate() {
@@ -494,9 +498,11 @@
         mMainChoreographer = Choreographer.getInstance();
         mAM = ActivityManagerWrapper.getInstance();
         mDeviceState = new RecentsAnimationDeviceState(this, true);
-        mTaskbarManager = new TaskbarManager(this);
+        mAllAppsActionManager = new AllAppsActionManager(
+                this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
+        mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
-        BootAwarePreloader.start(this);
+        mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
 
         // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
         LockedUserState.get(this).runOnUserUnlocked(this::onUserUnlocked);
@@ -543,13 +549,13 @@
 
     @UiThread
     public void onUserUnlocked() {
+        Log.d(TAG, "onUserUnlocked: userId=" + getUserId());
         mTaskAnimationManager = new TaskAnimationManager(this);
         mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
         mOverviewCommandHelper = new OverviewCommandHelper(this,
                 mOverviewComponentObserver, mTaskAnimationManager);
         mResetGestureInputConsumer = new ResetGestureInputConsumer(
                 mTaskAnimationManager, mTaskbarManager::getCurrentActivityContext);
-        mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
         mInputConsumer.registerInputConsumer();
         onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
         onAssistantVisibilityChanged();
@@ -586,52 +592,34 @@
     }
 
     private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
-        Executors.UI_HELPER_EXECUTOR.execute(() -> {
-            AccessibilityManager am = getSystemService(AccessibilityManager.class);
-
-            if (isHomeAndOverviewSame) {
-                am.registerSystemAction(
-                        createAllAppsAction(), GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
-            } else {
-                am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
-            }
-        });
+        mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame);
 
         StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
-                .getCreatedActivity();
+                .getCreatedContainer();
         if (newOverviewActivity != null) {
             mTaskbarManager.setActivity(newOverviewActivity);
         }
         mTISBinder.onOverviewTargetChange();
     }
 
-    private RemoteAction createAllAppsAction() {
-        final Intent homeIntent = new Intent(mOverviewComponentObserver.getHomeIntent())
-                .setAction(INTENT_ACTION_ALL_APPS_TOGGLE);
-        final PendingIntent actionPendingIntent;
-
+    private PendingIntent createAllAppsPendingIntent() {
         if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
-            actionPendingIntent = new PendingIntent(new IIntentSender.Stub() {
+            return new PendingIntent(new IIntentSender.Stub() {
                 @Override
                 public void send(int code, Intent intent, String resolvedType,
                         IBinder allowlistToken, IIntentReceiver finishedReceiver,
                         String requiredPermission, Bundle options) {
-                    MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps(homeIntent));
+                    MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps());
                 }
             });
         } else {
-            actionPendingIntent = PendingIntent.getActivity(
+            return PendingIntent.getActivity(
                     this,
                     GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
-                    homeIntent,
+                    new Intent(mOverviewComponentObserver.getHomeIntent())
+                            .setAction(INTENT_ACTION_ALL_APPS_TOGGLE),
                     PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
         }
-
-        return new RemoteAction(
-                Icon.createWithResource(this, R.drawable.ic_apps),
-                getString(R.string.all_apps_label),
-                getString(R.string.all_apps_label),
-                actionPendingIntent);
     }
 
     @UiThread
@@ -674,8 +662,7 @@
         mDeviceState.destroy();
         SystemUiProxy.INSTANCE.get(this).clearProxy();
 
-        getSystemService(AccessibilityManager.class)
-                .unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+        mAllAppsActionManager.onDestroy();
 
         mTaskbarManager.destroy();
         sConnected = false;
@@ -704,7 +691,7 @@
     private void onInputEvent(InputEvent ev) {
         if (!(ev instanceof MotionEvent)) {
             ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ")
-                    .append("Cannot process input event, received unknown event ")
+                    .append("Cannot process input event: received unknown event ")
                     .append(ev.toString()));
             return;
         }
@@ -717,27 +704,49 @@
         if (!isUserUnlocked || (mDeviceState.isButtonNavMode()
                 && !isTrackpadMotionEvent(event))) {
             ActiveGestureLog.INSTANCE.addLog(new CompoundString("TIS.onInputEvent: ")
-                    .append("Cannot process input event, ")
+                    .append("Cannot process input event: ")
                     .append(!isUserUnlocked
                             ? "user is locked"
                             : "using 3-button nav and event is not a trackpad event"));
             return;
         }
 
-        SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
-
         final int action = event.getActionMasked();
         // Note this will create a new consumer every mouse click, as after ACTION_UP from the click
         // an ACTION_HOVER_ENTER will fire as well.
-        boolean isHoverActionWithoutConsumer =
-                event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0;
+        boolean isHoverActionWithoutConsumer = enableCursorHoverStates()
+                && isHoverActionWithoutConsumer(event);
+
+        if (enableHandleDelayedGestureCallbacks()) {
+            if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+                mTaskAnimationManager.notifyNewGestureStart();
+            }
+            if (mTaskAnimationManager.shouldIgnoreMotionEvents()) {
+                if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
+                    ActiveGestureLog.INSTANCE.addLog(
+                            new CompoundString("TIS.onMotionEvent: A new gesture has been ")
+                                    .append("started, but a previously-requested recents ")
+                                    .append("animation hasn't started. Ignoring all following ")
+                                    .append("motion events."),
+                            RECENTS_ANIMATION_START_PENDING);
+                }
+                return;
+            }
+        }
+
+        SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
+
         CompoundString reasonString = action == ACTION_DOWN
-                ? new CompoundString("onMotionEvent: ") : CompoundString.NO_OP;
+                ? new CompoundString("TIS.onMotionEvent: ") : CompoundString.NO_OP;
         if (action == ACTION_DOWN || isHoverActionWithoutConsumer) {
             mRotationTouchHelper.setOrientationTransformIfNeeded(event);
 
             boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive();
             boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event);
+            TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+            if (isInSwipeUpTouchRegion && tac != null) {
+                tac.closeKeyboardQuickSwitchView();
+            }
             if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
                     || isHoverActionWithoutConsumer) {
                 reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion
@@ -749,7 +758,6 @@
                 GestureState prevGestureState = new GestureState(mGestureState);
                 GestureState newGestureState = createGestureState(mGestureState,
                         getTrackpadGestureType(event));
-                newGestureState.setSwipeUpStartTimeMs(SystemClock.uptimeMillis());
                 mConsumer.onConsumerAboutToBeSwitched();
                 mGestureState = newGestureState;
                 mConsumer = newConsumer(prevGestureState, mGestureState, event);
@@ -826,8 +834,8 @@
             }
         }
 
-        boolean cancelGesture = mGestureState.getActivityInterface() != null
-                && mGestureState.getActivityInterface().shouldCancelCurrentGesture();
+        boolean cancelGesture = mGestureState.getContainerInterface() != null
+                && mGestureState.getContainerInterface().shouldCancelCurrentGesture();
         boolean cleanUpConsumer = (action == ACTION_UP || action == ACTION_CANCEL || cancelGesture)
                 && mConsumer != null
                 && !mConsumer.getActiveConsumerInHierarchy().isConsumerDetachedFromGesture();
@@ -850,6 +858,15 @@
         traceToken.close();
     }
 
+    private boolean isHoverActionWithoutConsumer(MotionEvent event) {
+        // Only process these events when taskbar is present.
+        TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+        boolean isTaskbarPresent = tac != null && tac.getDeviceProfile().isTaskbarPresent
+                && !tac.isPhoneMode();
+        return event.isHoverEvent() && (mUncheckedConsumer.getType() & TYPE_CURSOR_HOVER) == 0
+                && isTaskbarPresent;
+    }
+
     // Talkback generates hover events on touch, which we do not want to consume.
     private boolean isCursorHoverEvent(MotionEvent event) {
         return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
@@ -978,8 +995,8 @@
             TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
             if (tac != null && !(base instanceof AssistantInputConsumer)) {
                 // Present always on large screen or on small screen w/ flag
-                DeviceProfile dp = tac.getDeviceProfile();
-                boolean useTaskbarConsumer = dp.isTaskbarPresent && !TaskbarManager.isPhoneMode(dp)
+                boolean useTaskbarConsumer = tac.getDeviceProfile().isTaskbarPresent
+                        && !tac.isPhoneMode()
                         && !tac.isInStashedLauncherState();
                 if (canStartSystemGesture && useTaskbarConsumer) {
                     reasonString.append(NEWLINE_PREFIX)
@@ -990,22 +1007,44 @@
                     base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
                             mOverviewCommandHelper);
                 }
-            } else if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) {
+            }
+            if (enableBubblesLongPressNavHandle()) {
+                // Create bubbles input consumer before NavHandleLongPressInputConsumer.
+                // This allows for nav handle to fall back to bubbles.
+                if (mDeviceState.isBubblesExpanded()) {
+                    reasonString = newCompoundString(reasonPrefix)
+                            .append(SUBSTRING_PREFIX)
+                            .append("bubbles expanded, trying to use default input consumer");
+                    // Bubbles can handle home gesture itself.
+                    base = getDefaultInputConsumer(reasonString);
+                }
+            }
+
+            NavHandle navHandle = tac != null ? tac.getNavHandle()
+                    : SystemUiProxy.INSTANCE.get(this);
+            if (canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()
+                    && navHandle.canNavHandleBeLongPressed()) {
                 reasonString.append(NEWLINE_PREFIX)
                         .append(reasonPrefix)
                         .append(SUBSTRING_PREFIX)
-                        .append("Not running recents animation, ")
-                        .append("using NavHandleLongPressInputConsumer");
+                        .append("Not running recents animation, ");
+                if (tac != null && tac.getNavHandle().canNavHandleBeLongPressed()) {
+                    reasonString.append("stashed handle is long-pressable, ");
+                }
+                reasonString.append("using NavHandleLongPressInputConsumer");
                 base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
-                        mDeviceState);
+                        mDeviceState, navHandle);
             }
 
-            if (mDeviceState.isBubblesExpanded()) {
-                reasonString = newCompoundString(reasonPrefix)
-                        .append(SUBSTRING_PREFIX)
-                        .append("bubbles expanded, trying to use default input consumer");
-                // Bubbles can handle home gesture itself.
-                base = getDefaultInputConsumer(reasonString);
+            if (!enableBubblesLongPressNavHandle()) {
+                // Continue overriding nav handle input consumer with bubbles
+                if (mDeviceState.isBubblesExpanded()) {
+                    reasonString = newCompoundString(reasonPrefix)
+                            .append(SUBSTRING_PREFIX)
+                            .append("bubbles expanded, trying to use default input consumer");
+                    // Bubbles can handle home gesture itself.
+                    base = getDefaultInputConsumer(reasonString);
+                }
             }
 
             if (mDeviceState.isSystemUiDialogShowing()) {
@@ -1113,7 +1152,7 @@
 
         TopTaskTracker.CachedTaskInfo runningTask = gestureState.getRunningTask();
         // Use overview input consumer for sharesheets on top of home.
-        boolean forceOverviewInputConsumer = gestureState.getActivityInterface().isStarted()
+        boolean forceOverviewInputConsumer = gestureState.getContainerInterface().isStarted()
                 && runningTask != null
                 && runningTask.isRootChooseActivity();
 
@@ -1132,13 +1171,22 @@
         }
 
         boolean previousGestureAnimatedToLauncher =
-                previousGestureState.isRunningAnimationToLauncher();
+                previousGestureState.isRunningAnimationToLauncher()
+                        || mDeviceState.isPredictiveBackToHomeInProgress();
         // with shell-transitions, home is resumed during recents animation, so
         // explicitly check against recents animation too.
         boolean launcherResumedThroughShellTransition =
-                gestureState.getActivityInterface().isResumed()
+                gestureState.getContainerInterface().isResumed()
                         && !previousGestureState.isRecentsAnimationRunning();
-        if (gestureState.getActivityInterface().isInLiveTileMode()) {
+        // If a task fragment within Launcher is resumed
+        boolean launcherChildActivityResumed = useActivityOverlay()
+                && runningTask != null
+                && runningTask.isHomeTask()
+                && mOverviewComponentObserver.isHomeAndOverviewSame()
+                && !launcherResumedThroughShellTransition
+                && !previousGestureState.isRecentsAnimationRunning();
+
+        if (gestureState.getContainerInterface().isInLiveTileMode()) {
             return createOverviewInputConsumer(
                     previousGestureState,
                     gestureState,
@@ -1164,9 +1212,11 @@
                                             ? "launcher resumed through a shell transition"
                                             : "forceOverviewInputConsumer == true"))
                             .append(", trying to use overview input consumer"));
-        } else if (mDeviceState.isGestureBlockedTask(runningTask)) {
+        } else if (mDeviceState.isGestureBlockedTask(runningTask) || launcherChildActivityResumed) {
             return getDefaultInputConsumer(reasonString.append(SUBSTRING_PREFIX)
-                    .append("is gesture-blocked task, trying to use default input consumer"));
+                    .append(launcherChildActivityResumed
+                            ? "is launcher child-task, trying to use default input consumer"
+                            : "is gesture-blocked task, trying to use default input consumer"));
         } else {
             reasonString.append(SUBSTRING_PREFIX)
                     .append("using OtherActivityInputConsumer");
@@ -1184,7 +1234,7 @@
 
         final AbsSwipeUpHandler.Factory factory = getSwipeUpHandlerFactory();
         final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
-                || gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
+                || gestureState.getContainerInterface().deferStartingActivity(mDeviceState, event);
         final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
         return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
                 gestureState, shouldDefer, this::onConsumerInactive,
@@ -1218,17 +1268,19 @@
             MotionEvent event,
             boolean forceOverviewInputConsumer,
             CompoundString reasonString) {
-        StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
-        if (activity == null) {
+        RecentsViewContainer container = gestureState.getContainerInterface().getCreatedContainer();
+        if (container == null) {
             return getDefaultInputConsumer(
                     reasonString.append(SUBSTRING_PREFIX)
                             .append("activity == null, trying to use default input consumer"));
         }
 
-        boolean hasWindowFocus = activity.getRootView().hasWindowFocus();
+        boolean hasWindowFocus = container.getRootView().hasWindowFocus();
         boolean isPreviousGestureAnimatingToLauncher =
-                previousGestureState.isRunningAnimationToLauncher();
-        boolean isInLiveTileMode = gestureState.getActivityInterface().isInLiveTileMode();
+                previousGestureState.isRunningAnimationToLauncher()
+                        || mDeviceState.isPredictiveBackToHomeInProgress();
+        boolean isInLiveTileMode = gestureState.getContainerInterface().isInLiveTileMode();
+
         reasonString.append(SUBSTRING_PREFIX)
                 .append(hasWindowFocus
                         ? "activity has window focus"
@@ -1242,14 +1294,14 @@
                 || isInLiveTileMode) {
             reasonString.append(SUBSTRING_PREFIX)
                     .append("overview should have focus, using OverviewInputConsumer");
-            return new OverviewInputConsumer(gestureState, activity, mInputMonitorCompat,
+            return new OverviewInputConsumer(gestureState, container, mInputMonitorCompat,
                     false /* startingInActivityBounds */);
         } else {
             reasonString.append(SUBSTRING_PREFIX).append(
                     "overview shouldn't have focus, using OverviewWithoutFocusInputConsumer");
             final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
-            return new OverviewWithoutFocusInputConsumer(activity, mDeviceState, gestureState,
-                    mInputMonitorCompat, disableHorizontalSwipe);
+            return new OverviewWithoutFocusInputConsumer(container.asContext(), mDeviceState,
+                    gestureState, mInputMonitorCompat, disableHorizontalSwipe);
         }
     }
 
@@ -1322,7 +1374,7 @@
                 mOverviewComponentObserver.getActivityInterface();
         final Intent overviewIntent = new Intent(
                 mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
-        if (activityInterface.getCreatedActivity() != null && fromInit) {
+        if (activityInterface.getCreatedContainer() != null && fromInit) {
             // The activity has been created before the initialization of overview service. It is
             // usually happens when booting or launcher is the top activity, so we should already
             // have the latest state.
@@ -1344,7 +1396,7 @@
         }
         final BaseActivityInterface activityInterface =
                 mOverviewComponentObserver.getActivityInterface();
-        final BaseDraggingActivity activity = activityInterface.getCreatedActivity();
+        final BaseDraggingActivity activity = activityInterface.getCreatedContainer();
         if (activity == null || activity.isStarted()) {
             // We only care about the existing background activity.
             return;
@@ -1374,7 +1426,6 @@
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] rawArgs) {
         // Dump everything
-        FlagsFactory.dump(pw);
         if (LockedUserState.get(this).isUserUnlocked()) {
             PluginManagerWrapper.INSTANCE.get(getBaseContext()).dump(pw);
         }
@@ -1386,29 +1437,33 @@
             mOverviewCommandHelper.dump(pw);
         }
         if (mGestureState != null) {
-            mGestureState.dump(pw);
+            mGestureState.dump("", pw);
         }
         pw.println("Input state:");
-        pw.println("  mInputMonitorCompat=" + mInputMonitorCompat);
-        pw.println("  mInputEventReceiver=" + mInputEventReceiver);
+        pw.println("\tmInputMonitorCompat=" + mInputMonitorCompat);
+        pw.println("\tmInputEventReceiver=" + mInputEventReceiver);
         DisplayController.INSTANCE.get(this).dump(pw);
         pw.println("TouchState:");
         BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
-                : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
+                : mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
         boolean resumed = mOverviewComponentObserver != null
                 && mOverviewComponentObserver.getActivityInterface().isResumed();
-        pw.println("  createdOverviewActivity=" + createdOverviewActivity);
-        pw.println("  resumed=" + resumed);
-        pw.println("  mConsumer=" + mConsumer.getName());
+        pw.println("\tcreatedOverviewActivity=" + createdOverviewActivity);
+        pw.println("\tresumed=" + resumed);
+        pw.println("\tmConsumer=" + mConsumer.getName());
         ActiveGestureLog.INSTANCE.dump("", pw);
         RecentsModel.INSTANCE.get(this).dump("", pw);
+        if (mTaskAnimationManager != null) {
+            mTaskAnimationManager.dump("", pw);
+        }
         if (createdOverviewActivity != null) {
             createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
         }
         mTaskbarManager.dumpLogs("", pw);
         pw.println("AssistStateManager:");
-        AssistStateManager.INSTANCE.get(this).dump("  ", pw);
+        AssistStateManager.INSTANCE.get(this).dump("\t", pw);
         SystemUiProxy.INSTANCE.get(this).dump(pw);
+        DeviceConfigWrapper.get().dump("   ", pw);
     }
 
     private AbsSwipeUpHandler createLauncherSwipeHandler(
diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
index b132067..3b58dfc 100644
--- a/quickstep/src/com/android/quickstep/ViewUtils.java
+++ b/quickstep/src/com/android/quickstep/ViewUtils.java
@@ -56,7 +56,7 @@
         boolean mSurfaceCallbackRegistered = false;
         boolean mFinished;
 
-        int mDeferFrameCount = 1;
+        int mDeferFrameCount = 2;
 
         FrameHandler(View view, Runnable finishCallback, BooleanSupplier cancelled) {
             mViewRoot = view.getViewRootImpl();
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 8a87f63..ec531d8 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -24,9 +24,9 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.TouchController;
-import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * In 0-button mode, intercepts swipe up from the nav bar on FallbackRecentsView to go home.
@@ -34,19 +34,19 @@
 public class FallbackNavBarTouchController implements TouchController,
         TriggerSwipeUpTouchTracker.OnSwipeUpListener {
 
-    private final RecentsActivity mActivity;
+    private final RecentsViewContainer mContainer;
     @Nullable
     private final TriggerSwipeUpTouchTracker mTriggerSwipeUpTracker;
 
-    public FallbackNavBarTouchController(RecentsActivity activity) {
-        mActivity = activity;
-        NavigationMode sysUINavigationMode = DisplayController.getNavigationMode(mActivity);
+    public FallbackNavBarTouchController(RecentsViewContainer container) {
+        mContainer = container;
+        NavigationMode sysUINavigationMode =
+                DisplayController.getNavigationMode(mContainer.asContext());
         if (sysUINavigationMode == NavigationMode.NO_BUTTON) {
             NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
-                    DisplayController.INSTANCE.get(mActivity).getInfo());
-            mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
-                    true /* disableHorizontalSwipe */, navBarPosition,
-                    null /* onInterceptTouch */, this);
+                    DisplayController.INSTANCE.get(mContainer.asContext()).getInfo());
+            mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mContainer.asContext(),
+                    true /* disableHorizontalSwipe */, navBarPosition, this);
         } else {
             mTriggerSwipeUpTracker = null;
         }
@@ -76,9 +76,6 @@
 
     @Override
     public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
-        mActivity.<FallbackRecentsView>getOverviewPanel().startHome();
+        mContainer.<FallbackRecentsView>getOverviewPanel().startHome();
     }
-
-    @Override
-    public void onSwipeUpCancelled() {}
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 8a9e04e..2e76356 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -38,6 +38,7 @@
 
 import android.util.FloatProperty;
 import android.util.Pair;
+import android.view.animation.Interpolator;
 
 import androidx.annotation.NonNull;
 
@@ -48,6 +49,9 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.views.ClearAllButton;
+import com.android.quickstep.views.OverviewActionsView;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * State controller for fallback recents activity
@@ -110,15 +114,13 @@
         setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
         boolean showAsGrid = state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile());
         setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
-                showAsGrid ? INSTANT : FINAL_FRAME);
+                getOverviewInterpolator(state));
         setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
-                state.showTaskThumbnailSplash() ? 1f : 0f, INSTANT);
+                state.showTaskThumbnailSplash() ? 1f : 0f, getOverviewInterpolator(state));
 
         setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
                 config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));
-
-        RecentsState currentState = mActivity.getStateManager().getState();
-        if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
+        if (isSplitSelectionState(state)) {
             int duration = state.getTransitionDuration(mActivity, true /* isToState */);
             // TODO (b/246851887): Pass in setter as a NO_ANIM PendingAnimation instead
             PendingAnimation pa = new PendingAnimation(duration);
@@ -126,7 +128,7 @@
             setter.add(pa.buildAnim());
         }
 
-        Pair<FloatProperty, FloatProperty> taskViewsFloat =
+        Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
                 mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
                         mActivity.getDeviceProfile());
@@ -135,6 +137,10 @@
         setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
     }
 
+    private Interpolator getOverviewInterpolator(RecentsState toState) {
+        return toState.overviewUi() ? INSTANT : FINAL_FRAME;
+    }
+
     /**
      * @return true if {@param toState} is {@link RecentsState#OVERVIEW_SPLIT_SELECT}
      */
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 35fa539..d881a1f 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -24,9 +24,7 @@
 import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
 
 import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
 import android.content.Context;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 
@@ -38,6 +36,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
 import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
@@ -55,7 +54,6 @@
 
 import java.util.ArrayList;
 
-@TargetApi(Build.VERSION_CODES.R)
 public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
         implements StateListener<RecentsState> {
 
@@ -70,7 +68,7 @@
 
     public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr, FallbackActivityInterface.INSTANCE);
-        mActivity.getStateManager().addStateListener(this);
+        mContainer.getStateManager().addStateListener(this);
     }
 
     @Override
@@ -83,13 +81,18 @@
 
     @Override
     protected void handleStartHome(boolean animated) {
-        mActivity.startHome();
-        AbstractFloatingView.closeAllOpenViews(mActivity, mActivity.isStarted());
+        mContainer.startHome();
+        AbstractFloatingView.closeAllOpenViews(mContainer, mContainer.isStarted());
     }
 
     @Override
     protected boolean canStartHomeSafely() {
-        return mActivity.canStartHomeSafely();
+        return mContainer.canStartHomeSafely();
+    }
+
+    @Override
+    public StateManager<RecentsState> getStateManager() {
+        return mContainer.getStateManager();
     }
 
     /**
@@ -213,11 +216,10 @@
     public void setModalStateEnabled(int taskId, boolean animate) {
         if (taskId != INVALID_TASK_ID) {
             setSelectedTask(taskId);
-            mActivity.getStateManager().goToState(RecentsState.MODAL_TASK, animate);
+            mContainer.getStateManager().goToState(RecentsState.MODAL_TASK, animate);
         } else {
-            if (mActivity.isInState(RecentsState.MODAL_TASK)) {
-                mActivity.getStateManager().goToState(DEFAULT, animate);
-                resetModalVisuals();
+            if (mContainer.isInState(RecentsState.MODAL_TASK)) {
+                mContainer.getStateManager().goToState(DEFAULT, animate);
             }
         }
     }
@@ -227,16 +229,18 @@
             @SplitConfigurationOptions.StagePosition int stagePosition,
             StatsLogManager.EventEnum splitEvent) {
         super.initiateSplitSelect(taskView, stagePosition, splitEvent);
-        mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
+        mContainer.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
     }
 
     @Override
     public void onStateTransitionStart(RecentsState toState) {
         setOverviewStateEnabled(true);
-        setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
+        setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mContainer.getDeviceProfile()));
         setOverviewFullscreenEnabled(toState.isFullScreen());
         if (toState == MODAL_TASK) {
             setOverviewSelectEnabled(true);
+        } else {
+            resetModalVisuals();
         }
 
         // Set border after select mode changes to avoid showing border during state transition
@@ -282,7 +286,7 @@
     public void setOverviewStateEnabled(boolean enabled) {
         super.setOverviewStateEnabled(enabled);
         if (enabled) {
-            RecentsState state = mActivity.getStateManager().getState();
+            RecentsState state = mContainer.getStateManager().getState();
             setDisallowScrollToClearAll(!state.hasClearAllButton());
         }
     }
@@ -291,17 +295,23 @@
     public boolean onTouchEvent(MotionEvent ev) {
         boolean result = super.onTouchEvent(ev);
         // Do not let touch escape to siblings below this view.
-        return result || mActivity.getStateManager().getState().overviewUi();
+        return result || mContainer.getStateManager().getState().overviewUi();
     }
 
     @Override
     public void initiateSplitSelect(SplitSelectSource splitSelectSource) {
         super.initiateSplitSelect(splitSelectSource);
-        mActivity.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
+        mContainer.getStateManager().goToState(OVERVIEW_SPLIT_SELECT);
     }
 
     @Override
     protected boolean canLaunchFullscreenTask() {
-        return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+        return !mContainer.isInState(OVERVIEW_SPLIT_SELECT);
+    }
+
+    /** Returns if app pairs are supported in this launcher. */
+    @Override
+    public boolean supportsAppPairs() {
+        return false;
     }
 }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 8b5f091..84937a2 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -26,7 +26,8 @@
 import com.android.launcher3.R;
 import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * State definition for Fallback recents
@@ -126,12 +127,13 @@
     /**
      * For this state, what color scrim should be drawn behind overview.
      */
-    public int getScrimColor(RecentsActivity activity) {
-        return hasFlag(FLAG_SCRIM) ? Themes.getAttrColor(activity, R.attr.overviewScrimColor)
+    public int getScrimColor(Context context) {
+        return hasFlag(FLAG_SCRIM)
+                ? Themes.getAttrColor(context, R.attr.overviewScrimColor)
                 : Color.TRANSPARENT;
     }
 
-    public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+    public float[] getOverviewScaleAndOffset(RecentsViewContainer container) {
         return new float[] { NO_SCALE, NO_OFFSET };
     }
 
@@ -161,8 +163,8 @@
         }
 
         @Override
-        public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
-            return getOverviewScaleAndOffsetForModalState(activity);
+        public float[] getOverviewScaleAndOffset(RecentsViewContainer container) {
+            return getOverviewScaleAndOffsetForModalState(container.getOverviewPanel());
         }
     }
 
@@ -172,8 +174,8 @@
         }
 
         @Override
-        public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
-            return getOverviewScaleAndOffsetForBackgroundState(activity);
+        public float[] getOverviewScaleAndOffset(RecentsViewContainer container) {
+            return getOverviewScaleAndOffsetForBackgroundState(container.getOverviewPanel());
         }
     }
 
@@ -183,7 +185,7 @@
         }
 
         @Override
-        public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
+        public float[] getOverviewScaleAndOffset(RecentsViewContainer container) {
             return new float[] { NO_SCALE, 1 };
         }
     }
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
index db4927a..2cb398c 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -26,7 +26,7 @@
 
     @Override
     protected boolean isRecentsInteractive() {
-        return mActivity.hasWindowFocus() || mActivity.getStateManager().getState().hasLiveTile();
+        return mContainer.hasWindowFocus() || mContainer.getStateManager().getState().hasLiveTile();
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
index ba012c9..222ccd3 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
@@ -43,13 +43,13 @@
 import android.view.ViewConfiguration;
 
 import com.android.app.animation.Interpolators;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
-import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 import java.util.function.Consumer;
@@ -78,7 +78,7 @@
     private float mTimeFraction;
     private long mDragTime;
     private float mLastProgress;
-    private BaseActivityInterface mActivityInterface;
+    private BaseContainerInterface mContainerInterface;
 
     private final float mDragDistThreshold;
     private final float mFlingDistThreshold;
@@ -106,7 +106,7 @@
         float slop = ViewConfiguration.get(context).getScaledTouchSlop();
 
         mSquaredSlop = slop * slop;
-        mActivityInterface = gestureState.getActivityInterface();
+        mContainerInterface = gestureState.getContainerInterface();
 
         boolean flingDisabled = deviceState.isAssistantGestureIsConstrained()
                 || deviceState.isInDeferredGestureRegion(startEvent);
@@ -237,9 +237,9 @@
     }
 
     private void startAssistantInternal() {
-        BaseDraggingActivity launcherActivity = mActivityInterface.getCreatedActivity();
-        if (launcherActivity != null) {
-            launcherActivity.getRootView().performHapticFeedback(
+        RecentsViewContainer container = mContainerInterface.getCreatedContainer();
+        if (container != null) {
+            container.getRootView().performHapticFeedback(
                 13, // HapticFeedbackConstants.GESTURE_END
                 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
         }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 4d47f07..1d00e53 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -22,6 +22,7 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.quickstep.NavHandle;
 
 /**
  * Class for extending nav handle long press behavior
@@ -42,19 +43,26 @@
      * A Runnable is returned here to ensure the InputConsumer can call
      * {@link android.view.InputMonitor#pilferPointers()} before invoking the long press behavior
      * since pilfering can break the long press behavior.
+     *
+     * @param navHandle to handle this long press
      */
-    public @Nullable Runnable getLongPressRunnable() {
+    public @Nullable Runnable getLongPressRunnable(NavHandle navHandle) {
         return null;
     }
 
     /**
      * Called when nav handle gesture starts.
+     *
+     * @param navHandle to handle the animation for this touch
      */
-    public void onTouchStarted() {}
+    public void onTouchStarted(NavHandle navHandle) {}
 
     /**
      * Called when nav handle gesture is finished by the user lifting their finger or the system
      * cancelling the touch for some other reason.
+     *
+     * @param navHandle to handle the animation for this touch
+     * @param reason why the touch ended
      */
-    public void onTouchFinished(String reason) {}
+    public void onTouchFinished(NavHandle navHandle, String reason) {}
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 0a558e2..075e539 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -15,23 +15,27 @@
  */
 package com.android.quickstep.inputconsumers;
 
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DEEP_PRESS_NAVBAR;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DEEP_PRESS_STASHED_TASKBAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_LONG_PRESS_NAVBAR;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_LONG_PRESS_STASHED_TASKBAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.LogConfig.NAV_HANDLE_LONG_PRESS;
 
 import android.content.Context;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
-import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.DeviceConfigWrapper;
 import com.android.quickstep.InputConsumer;
+import com.android.quickstep.NavHandle;
 import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.TopTaskTracker;
+import com.android.quickstep.util.AssistStateManager;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
@@ -39,14 +43,22 @@
  */
 public class NavHandleLongPressInputConsumer extends DelegateInputConsumer {
 
+    private static final String TAG = "NavHandleLongPressIC";
+    private static final boolean DEBUG_NAV_HANDLE = Utilities.isPropertyEnabled(
+            NAV_HANDLE_LONG_PRESS);
+
     private final NavHandleLongPressHandler mNavHandleLongPressHandler;
     private final float mNavHandleWidth;
     private final float mScreenWidth;
 
     private final Runnable mTriggerLongPress = this::triggerLongPress;
-    private final float mTouchSlopSquared;
+    private final float mTouchSlopSquaredOriginal;
+    private float mTouchSlopSquared;
+    private final float mOuterTouchSlopSquared;
     private final int mLongPressTimeout;
+    private final int mOuterLongPressTimeout;
     private final boolean mDeepPressEnabled;
+    private final NavHandle mNavHandle;
     private final StatsLogManager mStatsLogManager;
     private final TopTaskTracker mTopTaskTracker;
 
@@ -54,18 +66,30 @@
     private boolean mDeepPressLogged;  // Whether deep press has been logged for the current touch.
 
     public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
-            InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
+            InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState,
+            NavHandle navHandle) {
         super(delegate, inputMonitor);
-        mNavHandleWidth = context.getResources().getDimensionPixelSize(
-                R.dimen.navigation_home_handle_width);
         mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
-        mDeepPressEnabled = FeatureFlags.ENABLE_LPNH_DEEP_PRESS.get();
-        if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
-            mLongPressTimeout = LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_TIMEOUT_MS);
+        mDeepPressEnabled = DeviceConfigWrapper.get().getEnableLpnhDeepPress();
+        int twoStageMultiplier = DeviceConfigWrapper.get().getTwoStageMultiplier();
+        AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(context);
+        if (assistStateManager.getLPNHDurationMillis().isPresent()) {
+            mLongPressTimeout = assistStateManager.getLPNHDurationMillis().get().intValue();
         } else {
             mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
         }
-        mTouchSlopSquared = deviceState.getSquaredTouchSlop();
+        mOuterLongPressTimeout = mLongPressTimeout * twoStageMultiplier;
+        mTouchSlopSquaredOriginal = deviceState.getSquaredTouchSlop();
+        mTouchSlopSquared = mTouchSlopSquaredOriginal;
+        mOuterTouchSlopSquared = mTouchSlopSquared * (twoStageMultiplier * twoStageMultiplier);
+        if (DEBUG_NAV_HANDLE) {
+            Log.d(TAG, "mLongPressTimeout=" + mLongPressTimeout);
+            Log.d(TAG, "mOuterLongPressTimeout=" + mOuterLongPressTimeout);
+            Log.d(TAG, "mTouchSlopSquared=" + mTouchSlopSquared);
+            Log.d(TAG, "mOuterTouchSlopSquared=" + mOuterTouchSlopSquared);
+        }
+        mNavHandle = navHandle;
+        mNavHandleWidth = navHandle.getNavHandleWidth(context);
         mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);
         mStatsLogManager = StatsLogManager.newInstance(context);
         mTopTaskTracker = TopTaskTracker.INSTANCE.get(context);
@@ -89,6 +113,11 @@
         }
     }
 
+    @Override
+    public void onHoverEvent(MotionEvent ev) {
+        mDelegate.onHoverEvent(ev);
+    }
+
     private void handleMotionEvent(MotionEvent ev) {
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN -> {
@@ -96,11 +125,14 @@
                     mCurrentDownEvent.recycle();
                 }
                 mCurrentDownEvent = MotionEvent.obtain(ev);
+                mTouchSlopSquared = mTouchSlopSquaredOriginal;
                 mDeepPressLogged = false;
                 if (isInNavBarHorizontalArea(ev.getRawX())) {
-                    mNavHandleLongPressHandler.onTouchStarted();
-                    MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress,
-                            mLongPressTimeout);
+                    mNavHandleLongPressHandler.onTouchStarted(mNavHandle);
+                    MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress, mLongPressTimeout);
+                }
+                if (DEBUG_NAV_HANDLE) {
+                    Log.d(TAG, "ACTION_DOWN");
                 }
             }
             case MotionEvent.ACTION_MOVE -> {
@@ -108,11 +140,29 @@
                     break;
                 }
 
-                float touchSlopSquared = mTouchSlopSquared;
                 float dx = ev.getX() - mCurrentDownEvent.getX();
                 float dy = ev.getY() - mCurrentDownEvent.getY();
                 double distanceSquared = (dx * dx) + (dy * dy);
-                if (distanceSquared > touchSlopSquared) {
+                if (DEBUG_NAV_HANDLE) {
+                    Log.d(TAG, "ACTION_MOVE distanceSquared=" + distanceSquared);
+                }
+                if (DeviceConfigWrapper.get().getEnableLpnhTwoStages()) {
+                    if (mTouchSlopSquared < distanceSquared
+                            && distanceSquared <= mOuterTouchSlopSquared) {
+                        MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
+                        int delay = mOuterLongPressTimeout
+                                - (int) (ev.getEventTime() - ev.getDownTime());
+                        MAIN_EXECUTOR.getHandler().postDelayed(mTriggerLongPress, delay);
+                        mTouchSlopSquared = mOuterTouchSlopSquared;
+                        if (DEBUG_NAV_HANDLE) {
+                            Log.d(TAG, "Touch in middle region!");
+                        }
+                    }
+                }
+                if (distanceSquared > mTouchSlopSquared) {
+                    if (DEBUG_NAV_HANDLE) {
+                        Log.d(TAG, "Touch slop out. mTouchSlopSquared=" + mTouchSlopSquared);
+                    }
                     cancelLongPress("touch slop passed");
                 }
             }
@@ -127,8 +177,9 @@
             // Log deep press even if feature is disabled.
             String runningPackage = mTopTaskTracker.getCachedTopTask(
                     /* filterOnlyVisibleRecents */ true).getPackageName();
-            mStatsLogManager.logger().withPackageName(runningPackage)
-                    .log(LAUNCHER_DEEP_PRESS_NAVBAR);
+            mStatsLogManager.logger().withPackageName(runningPackage).log(
+                    mNavHandle.isNavHandleStashedTaskbar() ? LAUNCHER_DEEP_PRESS_STASHED_TASKBAR
+                            : LAUNCHER_DEEP_PRESS_NAVBAR);
             mDeepPressLogged = true;
 
             // But only trigger if the feature is enabled.
@@ -140,11 +191,16 @@
     }
 
     private void triggerLongPress() {
+        if (DEBUG_NAV_HANDLE) {
+            Log.d(TAG, "triggerLongPress");
+        }
         String runningPackage = mTopTaskTracker.getCachedTopTask(
                 /* filterOnlyVisibleRecents */ true).getPackageName();
-        mStatsLogManager.logger().withPackageName(runningPackage).log(LAUNCHER_LONG_PRESS_NAVBAR);
+        mStatsLogManager.logger().withPackageName(runningPackage).log(
+                mNavHandle.isNavHandleStashedTaskbar() ? LAUNCHER_LONG_PRESS_STASHED_TASKBAR
+                        : LAUNCHER_LONG_PRESS_NAVBAR);
 
-        Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable();
+        Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable(mNavHandle);
         if (longPressRunnable == null) {
             return;
         }
@@ -160,12 +216,24 @@
     }
 
     private void cancelLongPress(String reason) {
+        if (DEBUG_NAV_HANDLE) {
+            Log.d(TAG, "cancelLongPress");
+        }
         MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
-        mNavHandleLongPressHandler.onTouchFinished(reason);
+        mNavHandleLongPressHandler.onTouchFinished(mNavHandle, reason);
     }
 
     private boolean isInNavBarHorizontalArea(float x) {
         float areaFromMiddle = mNavHandleWidth / 2.0f;
+        if (DeviceConfigWrapper.get().getCustomLpnhThresholds()) {
+            areaFromMiddle += Utilities.dpToPx(
+                    DeviceConfigWrapper.get().getLpnhExtraTouchWidthDp());
+        }
+        int minAccessibleSize = Utilities.dpToPx(24);  // Half of 48dp because this is per side.
+        if (areaFromMiddle < minAccessibleSize) {
+            Log.w(TAG, "Custom nav handle region is too small - resetting to 48dp");
+            areaFromMiddle = minAccessibleSize;
+        }
         float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);
 
         return distFromMiddle < areaFromMiddle;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index eedd204..9f39476 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -31,12 +31,10 @@
 import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.graphics.PointF;
-import android.os.Build;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -51,7 +49,6 @@
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.AbsSwipeUpHandler;
 import com.android.quickstep.AbsSwipeUpHandler.Factory;
-import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.RecentsAnimationCallbacks;
@@ -71,7 +68,6 @@
 /**
  * Input consumer for handling events originating from an activity other than Launcher
  */
-@TargetApi(Build.VERSION_CODES.P)
 public class OtherActivityInputConsumer extends ContextWrapper implements InputConsumer {
 
     public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN";
@@ -89,8 +85,6 @@
     private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
     private final InputMonitorCompat mInputMonitorCompat;
     private final InputEventReceiver mInputEventReceiver;
-    private final BaseActivityInterface mActivityInterface;
-
     private final AbsSwipeUpHandler.Factory mHandlerFactory;
 
     private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
@@ -138,7 +132,6 @@
         mTaskAnimationManager = taskAnimationManager;
         mGestureState = gestureState;
         mHandlerFactory = handlerFactory;
-        mActivityInterface = mGestureState.getActivityInterface();
 
         mMotionPauseDetector = new MotionPauseDetector(base, false,
                 mNavBarPosition.isLeftEdge() || mNavBarPosition.isRightEdge()
@@ -157,6 +150,7 @@
         mSquaredTouchSlop = mDeviceState.getSquaredTouchSlop();
 
         mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
+        mStartDisplacement = continuingPreviousGesture ? 0 : -mTouchSlop;
         mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
     }
@@ -283,7 +277,7 @@
                         if (mGestureState.isTrackpadGesture() || Math.abs(displacement)
                                 > mTouchSlop) {
                             mPassedWindowMoveSlop = true;
-                            mStartDisplacement = Math.min(displacement, -mTouchSlop);
+                            mStartDisplacement = -mTouchSlop;
                         }
                     }
                 }
@@ -339,7 +333,7 @@
                         }
                         if (!mPassedWindowMoveSlop) {
                             mPassedWindowMoveSlop = true;
-                            mStartDisplacement = Math.min(displacement, -mTouchSlop);
+                            mStartDisplacement = -mTouchSlop;
                         }
                         notifyGestureStarted(isLikelyToStartNewTask);
                     }
@@ -396,7 +390,8 @@
         mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs);
         mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
         mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener());
-        mInteractionHandler.initWhenReady();
+        mInteractionHandler.initWhenReady(
+                "OtherActivityInputConsumer.startTouchTrackingForWindowAnimation");
 
         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
             mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 7d3a860..bb8d1d7 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -28,24 +28,24 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.statemanager.BaseState;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
  * Input consumer for handling touch on the recents/Launcher activity.
  */
-public class OverviewInputConsumer<S extends BaseState<S>, T extends StatefulActivity<S>>
+public class OverviewInputConsumer<S extends BaseState<S>, T extends RecentsViewContainer>
         implements InputConsumer {
 
-    private final T mActivity;
-    private final BaseActivityInterface<?, T> mActivityInterface;
+    private final T mContainer;
+    private final BaseContainerInterface<?, T> mContainerInterface;
     private final BaseDragLayer mTarget;
     private final InputMonitorCompat mInputMonitor;
 
@@ -56,14 +56,14 @@
     private boolean mHasSetTouchModeForFirstDPadEvent;
     private boolean mIsWaitingForAttachToWindow;
 
-    public OverviewInputConsumer(GestureState gestureState, T activity,
+    public OverviewInputConsumer(GestureState gestureState, T container,
             @Nullable InputMonitorCompat inputMonitor, boolean startingInActivityBounds) {
-        mActivity = activity;
+        mContainer = container;
         mInputMonitor = inputMonitor;
         mStartingInActivityBounds = startingInActivityBounds;
-        mActivityInterface = gestureState.getActivityInterface();
+        mContainerInterface = gestureState.getContainerInterface();
 
-        mTarget = activity.getDragLayer();
+        mTarget = container.getDragLayer();
         mTarget.getLocationOnScreen(mLocationOnScreen);
     }
 
@@ -91,7 +91,7 @@
         if (!mTargetHandledTouch && handled) {
             mTargetHandledTouch = true;
             if (!mStartingInActivityBounds) {
-                mActivityInterface.closeOverlay();
+                mContainerInterface.closeOverlay();
                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
             }
             if (mInputMonitor != null) {
@@ -100,13 +100,13 @@
             }
         }
         if (mHasSetTouchModeForFirstDPadEvent) {
-            mActivity.getRootView().clearFocus();
+            mContainer.getRootView().clearFocus();
         }
     }
 
     @Override
     public void onHoverEvent(MotionEvent ev) {
-        mActivity.dispatchGenericMotionEvent(ev);
+        mContainer.dispatchGenericMotionEvent(ev);
     }
 
     @Override
@@ -115,7 +115,8 @@
             case KeyEvent.KEYCODE_VOLUME_DOWN:
             case KeyEvent.KEYCODE_VOLUME_UP:
             case KeyEvent.KEYCODE_VOLUME_MUTE:
-                MediaSessionManager mgr = mActivity.getSystemService(MediaSessionManager.class);
+                MediaSessionManager mgr = mContainer.asContext()
+                        .getSystemService(MediaSessionManager.class);
                 mgr.dispatchVolumeKeyEventAsSystemService(ev,
                         AudioManager.USE_DEFAULT_STREAM_TYPE);
                 break;
@@ -124,7 +125,7 @@
                 if (mHasSetTouchModeForFirstDPadEvent) {
                     break;
                 }
-                View viewRoot = mActivity.getRootView();
+                View viewRoot = mContainer.getRootView();
                 if (viewRoot.isAttachedToWindow()) {
                     setTouchModeChanged(viewRoot);
                     break;
@@ -150,7 +151,7 @@
             default:
                 break;
         }
-        mActivity.dispatchKeyEvent(ev);
+        mContainer.dispatchKeyEvent(ev);
     }
 
     private void setTouchModeChanged(@NonNull View viewRoot) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
index 41730bb..42e8694 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
@@ -51,7 +51,7 @@
         mGestureState = gestureState;
         mInputMonitor = inputMonitor;
         mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, disableHorizontalSwipe,
-                deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+                deviceState.getNavBarPosition(), this);
     }
 
     @Override
@@ -69,7 +69,8 @@
         mTriggerSwipeUpTracker.onMotionEvent(ev);
     }
 
-    private void onInterceptTouch() {
+    @Override
+    public void onSwipeUpTouchIntercepted() {
         if (mInputMonitor != null) {
             TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
             mInputMonitor.pilferPointers();
@@ -93,7 +94,4 @@
                         .build())
                 .log(LAUNCHER_HOME_GESTURE);
     }
-
-    @Override
-    public void onSwipeUpCancelled() {}
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
index a8bf333..d73c23f 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
@@ -19,12 +19,12 @@
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.MotionPauseDetector;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * An input consumer that detects swipe up and hold to exit screen pinning mode.
@@ -44,10 +44,10 @@
         mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/);
         mMotionPauseDetector.setOnMotionPauseListener(() -> {
             SystemUiProxy.INSTANCE.get(context).stopScreenPinning();
-            BaseDraggingActivity launcherActivity = gestureState.getActivityInterface()
-                    .getCreatedActivity();
-            if (launcherActivity != null) {
-                launcherActivity.getRootView().performHapticFeedback(
+            RecentsViewContainer container = gestureState.getContainerInterface()
+                    .getCreatedContainer();
+            if (container != null) {
+                container.getRootView().performHapticFeedback(
                         HapticFeedbackConstants.LONG_PRESS,
                         HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
             }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
index 4806ac1..871d075 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
@@ -54,7 +54,7 @@
         mContext = context;
         mInputMonitor = inputMonitor;
         mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, true,
-                deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+                deviceState.getNavBarPosition(), this);
     }
 
     @Override
@@ -72,7 +72,8 @@
         mTriggerSwipeUpTracker.onMotionEvent(ev);
     }
 
-    private void onInterceptTouch() {
+    @Override
+    public void onSwipeUpTouchIntercepted() {
         if (mInputMonitor != null) {
             TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
             mInputMonitor.pilferPointers();
@@ -88,9 +89,4 @@
             Log.e(TAG, "Exception calling closeSystemDialogs " + e.getMessage());
         }
     }
-
-    @Override
-    public void onSwipeUpCancelled() {
-
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 404bca9..6757cd8 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -85,7 +85,9 @@
     public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.back_gesture_feedback_complete_without_follow_up
-                : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+                : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+                        ? R.string.back_gesture_feedback_complete_with_follow_up
+                        : R.string.back_gesture_feedback_complete_with_overview_follow_up;
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index a36f501..4f1dbbe 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -54,10 +54,11 @@
     static final String KEY_TUTORIAL_TYPE = "tutorial_type";
     static final String KEY_GESTURE_COMPLETE = "gesture_complete";
     static final String KEY_USE_TUTORIAL_MENU = "use_tutorial_menu";
+    public static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
+    public static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
 
     @Nullable private TutorialType[] mTutorialSteps;
     private GestureSandboxFragment mCurrentFragment;
-    private GestureSandboxFragment mPendingFragment;
 
     private int mCurrentStep;
     private int mNumSteps;
@@ -159,32 +160,32 @@
      * Gesture animations are only in landscape for large screens and portrait for mobile. This
      * method enforces the following flows:
      *     1) phone / two-panel closed -> lock to portrait
-     *     2) two-panel open / tablet + portrait -> prompt the user to rotate the screen
-     *     3) two-panel open / tablet + landscape -> hide potential rotating prompt
+     *     2) Large screen + portrait -> prompt the user to rotate the screen
+     *     3) Large screen + landscape -> hide potential rotating prompt
+     *     4) Square aspect ratio -> no action taken as the animations will fit both orientations
      */
     private void correctUserOrientation() {
         DeviceProfile deviceProfile = InvariantDeviceProfile.INSTANCE.get(
                 getApplicationContext()).getDeviceProfile(this);
         if (deviceProfile.isTablet) {
-            boolean showRotationPrompt = getResources().getConfiguration().orientation
+            // The tutorial will work in either orientation if the height and width are similar
+            boolean isAspectRatioSquare =
+                    deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
+                            && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND;
+            boolean showRotationPrompt = !isAspectRatioSquare
+                    && getResources().getConfiguration().orientation
                     == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
-            GestureSandboxFragment recreatedFragment =
-                    showRotationPrompt || mPendingFragment == null
-                            ? null : mPendingFragment.recreateFragment();
             showFragment(showRotationPrompt
                     ? new RotationPromptFragment()
-                    : recreatedFragment == null
-                            ? mCurrentFragment : recreatedFragment);
+                    : mCurrentFragment.canRecreateFragment()
+                            ? mCurrentFragment.recreateFragment() : mCurrentFragment);
         } else {
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
         }
     }
 
     private void showFragment(@NonNull GestureSandboxFragment fragment) {
-        if (mCurrentFragment.recreateFragment() != null) {
-            mPendingFragment = mCurrentFragment;
-        }
         mCurrentFragment = fragment;
         getSupportFragmentManager().beginTransaction()
                 .replace(R.id.gesture_tutorial_fragment_container, mCurrentFragment)
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxFragment.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxFragment.java
index 08f2989..03bdd5d 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxFragment.java
@@ -28,6 +28,10 @@
 
     void onDetachedFromWindow() {}
 
+    boolean canRecreateFragment() {
+        return false;
+    }
+
     @Nullable
     GestureSandboxFragment recreateFragment() {
         return null;
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index df552cf..1129e02 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -17,9 +17,7 @@
 
 import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
 
-import android.annotation.TargetApi;
 import android.graphics.PointF;
-import android.os.Build;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -30,7 +28,6 @@
 import java.util.Map;
 
 /** A {@link TutorialController} for the Home tutorial. */
-@TargetApi(Build.VERSION_CODES.R)
 final class HomeGestureTutorialController extends SwipeUpGestureTutorialController {
 
     HomeGestureTutorialController(HomeGestureTutorialFragment fragment, TutorialType tutorialType) {
diff --git a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
index dbf141b..8ead3dd 100644
--- a/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/MenuFragment.java
@@ -39,6 +39,11 @@
     }
 
     @Override
+    boolean canRecreateFragment() {
+        return true;
+    }
+
+    @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
             @Nullable Bundle savedInstanceState) {
         final View root = inflater.inflate(
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index c4a2216..c00f508 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -65,7 +65,7 @@
         mSwipeUpTouchTracker =
                 new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
                         new NavBarPosition(NavigationMode.NO_BUTTON, displayInfo),
-                        null /*onInterceptTouch*/, this);
+                        this);
         mMotionPauseDetector = new MotionPauseDetector(context);
 
         final Resources resources = context.getResources();
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 65f3a01..a04dd44 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -21,9 +21,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.annotation.TargetApi;
 import android.graphics.PointF;
-import android.os.Build;
 import android.os.Handler;
 
 import androidx.annotation.ColorInt;
@@ -42,7 +40,6 @@
 import java.util.Map;
 
 /** A {@link TutorialController} for the Overview tutorial. */
-@TargetApi(Build.VERSION_CODES.R)
 final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
 
     private static final float LAUNCHER_COLOR_BLENDING_RATIO = 0.4f;
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 87defc5..d5cc447 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -29,13 +29,11 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Outline;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 
@@ -63,7 +61,6 @@
 import com.android.quickstep.util.SurfaceTransaction.MockProperties;
 import com.android.quickstep.util.TransformParams;
 
-@TargetApi(Build.VERSION_CODES.R)
 abstract class SwipeUpGestureTutorialController extends TutorialController {
 
     private static final int FAKE_PREVIOUS_TASK_MARGIN = Utilities.dpToPx(24);
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 545a94d..f89888a 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -41,6 +41,7 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -87,7 +88,7 @@
     private static final int FEEDBACK_ANIMATION_MS = 133;
     private static final int RIPPLE_VISIBLE_MS = 300;
     private static final int GESTURE_ANIMATION_DELAY_MS = 1500;
-    private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 2000;
+    private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 3000;
     private static final long GESTURE_ANIMATION_PAUSE_DURATION_MILLIS = 1000;
     protected float mExitingAppEndingCornerRadius;
     protected float mExitingAppStartingCornerRadius;
@@ -209,8 +210,12 @@
                                 mFeedbackView.removeCallbacks(mFeedbackViewCallback);
                             }
                             mFeedbackViewCallback = mTutorialFragment::continueTutorial;
-                            mFeedbackView.postDelayed(mFeedbackViewCallback,
-                                    ADVANCE_TUTORIAL_TIMEOUT_MS);
+                            mFeedbackView.postDelayed(
+                                    mFeedbackViewCallback,
+                                    AccessibilityManager.getInstance(mContext)
+                                            .getRecommendedTimeoutMillis(
+                                                    ADVANCE_TUTORIAL_TIMEOUT_MS,
+                                                    AccessibilityManager.FLAG_CONTENT_TEXT));
                         }
                     })
                     .start();
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index c91ee81..0fafb94 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -114,6 +114,11 @@
         return newInstance(tutorialType, isGestureComplete(), mFromTutorialMenu);
     }
 
+    @Override
+    boolean canRecreateFragment() {
+        return true;
+    }
+
     @NonNull
     abstract TutorialType getDefaultTutorialType();
 
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index bce2e82..ed633df 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -42,6 +42,7 @@
 import androidx.annotation.WorkerThread;
 import androidx.slice.SliceItem;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logger.LauncherAtom;
@@ -60,7 +61,7 @@
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LogConfig;
@@ -112,7 +113,7 @@
             new CopyOnWriteArrayList<>();
 
     public StatsLogCompatManager(Context context) {
-        mContext = context;
+        super(context);
     }
 
     @Override
@@ -138,7 +139,7 @@
         if (IS_VERBOSE) {
             Log.d(TAG, String.format("\nwriteSnapshot(%d):\n%s", instanceId.getId(), info));
         }
-        if (!Utilities.ATLEAST_R || Utilities.isRunningInTestHarness()) {
+        if (Utilities.isRunningInTestHarness()) {
             return;
         }
         SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
@@ -341,15 +342,11 @@
 
         @Override
         public void log(EventEnum event) {
-            if (!Utilities.ATLEAST_R) {
-                return;
-            }
             if (DEBUG) {
                 String name = (event instanceof Enum) ? ((Enum) event).name() :
                         event.getId() + "";
                 Log.d(TAG, name);
             }
-            LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
 
             if (mSlice == null && mSliceItem != null) {
                 mSlice = LauncherAtom.Slice.newBuilder().setUri(
@@ -371,24 +368,25 @@
                 return;
             }
 
-            if (mItemInfo.container < 0 || appState == null) {
-                // Write log on the model thread so that logs do not go out of order
-                // (for eg: drop comes after drag)
-                Executors.MODEL_EXECUTOR.execute(
-                        () -> write(event, applyOverwrites(mItemInfo.buildProto())));
-            } else {
-                // Item is inside the folder, fetch folder info in a BG thread
+            if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
+                // Item is inside a collection, fetch collection info in a BG thread
                 // and then write to StatsLog.
-                appState.getModel().enqueueModelUpdateTask(
+                app.getModel().enqueueModelUpdateTask(
                         new BaseModelUpdateTask() {
                             @Override
                             public void execute(@NonNull final LauncherAppState app,
                                     @NonNull final BgDataModel dataModel,
                                     @NonNull final AllAppsList apps) {
-                                FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
-                                write(event, applyOverwrites(mItemInfo.buildProto(folderInfo)));
+                                CollectionInfo collectionInfo =
+                                        dataModel.collections.get(mItemInfo.container);
+                                write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
                             }
                         });
+            })) {
+                // Write log on the model thread so that logs do not go out of order
+                // (for eg: drop comes after drag)
+                Executors.MODEL_EXECUTOR.execute(
+                        () -> write(event, applyOverwrites(mItemInfo.buildProto())));
             }
         }
 
@@ -401,11 +399,10 @@
                 case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN:
                     InteractionJankMonitorWrapper.begin(
                             view,
-                            InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL);
+                            Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
                     break;
                 case LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END:
-                    InteractionJankMonitorWrapper.end(
-                            InteractionJankMonitorWrapper.CUJ_ALL_APPS_SCROLL);
+                    InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_ALL_APPS_SCROLL);
                     break;
                 default:
                     break;
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
new file mode 100644
index 0000000..1640104
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.annotation.SuppressLint
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.ShapeDrawable
+import android.util.FloatProperty
+import android.util.Pair
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.VelocityTracker
+import android.view.View
+import android.view.View.MeasureSpec
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherAnimUtils
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.touch.PagedOrientationHandler.ChildBounds
+import com.android.launcher3.touch.PagedOrientationHandler.Float2DAction
+import com.android.launcher3.touch.PagedOrientationHandler.Int2DAction
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.views.IconAppChipView
+import kotlin.math.max
+
+open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
+    override fun <T> getPrimaryValue(x: T, y: T): T = y
+
+    override fun <T> getSecondaryValue(x: T, y: T): T = x
+
+    override fun getPrimaryValue(x: Int, y: Int): Int = y
+
+    override fun getSecondaryValue(x: Int, y: Int): Int = x
+
+    override fun getPrimaryValue(x: Float, y: Float): Float = y
+
+    override fun getSecondaryValue(x: Float, y: Float): Float = x
+
+    override val isLayoutNaturalToLauncher: Boolean = false
+
+    override fun adjustFloatingIconStartVelocity(velocity: PointF) {
+        val oldX = velocity.x
+        val oldY = velocity.y
+        velocity.set(-oldY, oldX)
+    }
+
+    override fun fixBoundsForHomeAnimStartRect(outStartRect: RectF, deviceProfile: DeviceProfile) {
+        // We don't need to check the "top" value here because the startRect is in the orientation
+        // of the app, not of the fixed portrait launcher.
+        if (outStartRect.left > deviceProfile.heightPx) {
+            outStartRect.offsetTo(0f, outStartRect.top)
+        } else if (outStartRect.left < -deviceProfile.heightPx) {
+            outStartRect.offsetTo(0f, outStartRect.top)
+        }
+    }
+
+    override fun <T> setPrimary(target: T, action: Int2DAction<T>, param: Int) =
+        action.call(target, 0, param)
+
+    override fun <T> setPrimary(target: T, action: Float2DAction<T>, param: Float) =
+        action.call(target, 0f, param)
+
+    override fun <T> setSecondary(target: T, action: Float2DAction<T>, param: Float) =
+        action.call(target, param, 0f)
+
+    override fun <T> set(
+        target: T,
+        action: Int2DAction<T>,
+        primaryParam: Int,
+        secondaryParam: Int
+    ) = action.call(target, secondaryParam, primaryParam)
+
+    override fun getPrimaryDirection(event: MotionEvent, pointerIndex: Int): Float =
+        event.getY(pointerIndex)
+
+    override fun getPrimaryVelocity(velocityTracker: VelocityTracker, pointerId: Int): Float =
+        velocityTracker.getYVelocity(pointerId)
+
+    override fun getMeasuredSize(view: View): Int = view.measuredHeight
+
+    override fun getPrimarySize(view: View): Int = view.height
+
+    override fun getPrimarySize(rect: RectF): Float = rect.height()
+
+    override fun getStart(rect: RectF): Float = rect.top
+
+    override fun getEnd(rect: RectF): Float = rect.bottom
+
+    override fun getClearAllSidePadding(view: View, isRtl: Boolean): Int =
+        if (isRtl) view.paddingBottom / 2 else -view.paddingTop / 2
+
+    override fun getSecondaryDimension(view: View): Int = view.width
+
+    override val primaryViewTranslate: FloatProperty<View> = LauncherAnimUtils.VIEW_TRANSLATE_Y
+
+    override val secondaryViewTranslate: FloatProperty<View> = LauncherAnimUtils.VIEW_TRANSLATE_X
+
+    override fun getPrimaryScroll(view: View): Int = view.scrollY
+
+    override fun getPrimaryScale(view: View): Float = view.scaleY
+
+    override fun setMaxScroll(event: AccessibilityEvent, maxScroll: Int) {
+        event.maxScrollY = maxScroll
+    }
+
+    override fun getRecentsRtlSetting(resources: Resources): Boolean = !Utilities.isRtl(resources)
+
+    override val degreesRotated: Float = 90f
+
+    override val rotation: Int = Surface.ROTATION_90
+
+    override fun setPrimaryScale(view: View, scale: Float) {
+        view.scaleY = scale
+    }
+
+    override fun setSecondaryScale(view: View, scale: Float) {
+        view.scaleX = scale
+    }
+
+    override fun getChildStart(view: View): Int = view.top
+
+    override fun getCenterForPage(view: View, insets: Rect): Int =
+        (view.paddingLeft + view.measuredWidth + insets.left - insets.right - view.paddingRight) / 2
+
+    override fun getScrollOffsetStart(view: View, insets: Rect): Int = insets.top + view.paddingTop
+
+    override fun getScrollOffsetEnd(view: View, insets: Rect): Int =
+        view.height - view.paddingBottom - insets.bottom
+
+    override val secondaryTranslationDirectionFactor: Int = 1
+
+    override fun getSplitTranslationDirectionFactor(
+        stagePosition: Int,
+        deviceProfile: DeviceProfile
+    ): Int = if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) -1 else 1
+
+    override fun getTaskMenuX(
+        x: Float,
+        thumbnailView: View,
+        deviceProfile: DeviceProfile,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float = thumbnailView.measuredWidth + x - taskInsetMargin
+
+    override fun getTaskMenuY(
+        y: Float,
+        thumbnailView: View,
+        stagePosition: Int,
+        taskMenuView: View,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float {
+        val layoutParams = taskMenuView.layoutParams as BaseDragLayer.LayoutParams
+        var taskMenuY = y + taskInsetMargin
+
+        if (stagePosition == STAGE_POSITION_UNDEFINED) {
+            taskMenuY += (thumbnailView.measuredHeight - layoutParams.width) / 2f
+        }
+
+        return taskMenuY
+    }
+
+    override fun getTaskMenuWidth(
+        thumbnailView: View,
+        deviceProfile: DeviceProfile,
+        @StagePosition stagePosition: Int
+    ): Int =
+        when {
+            Flags.enableOverviewIconMenu() ->
+                thumbnailView.resources.getDimensionPixelSize(
+                    R.dimen.task_thumbnail_icon_menu_expanded_width
+                )
+            stagePosition == STAGE_POSITION_UNDEFINED -> thumbnailView.measuredWidth
+            else -> thumbnailView.measuredHeight
+        }
+
+    override fun getTaskMenuHeight(
+        taskInsetMargin: Float,
+        deviceProfile: DeviceProfile,
+        taskMenuX: Float,
+        taskMenuY: Float
+    ): Int = (taskMenuX - taskInsetMargin).toInt()
+
+    override fun setTaskOptionsMenuLayoutOrientation(
+        deviceProfile: DeviceProfile,
+        taskMenuLayout: LinearLayout,
+        dividerSpacing: Int,
+        dividerDrawable: ShapeDrawable
+    ) {
+        taskMenuLayout.orientation = LinearLayout.VERTICAL
+        dividerDrawable.intrinsicHeight = dividerSpacing
+        taskMenuLayout.dividerDrawable = dividerDrawable
+    }
+
+    override fun setLayoutParamsForTaskMenuOptionItem(
+        lp: LinearLayout.LayoutParams,
+        viewGroup: LinearLayout,
+        deviceProfile: DeviceProfile
+    ) {
+        // Phone fake landscape
+        viewGroup.orientation = LinearLayout.HORIZONTAL
+        lp.width = ViewGroup.LayoutParams.MATCH_PARENT
+        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
+    }
+
+    override fun getDwbLayoutTranslations(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        splitBounds: SplitBounds?,
+        deviceProfile: DeviceProfile,
+        thumbnailViews: Array<View>,
+        desiredTaskId: Int,
+        banner: View
+    ): Pair<Float, Float> {
+        val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
+        val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
+        val translationX = banner.height.toFloat()
+
+        val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
+        bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START
+        banner.pivotX = 0f
+        banner.pivotY = 0f
+        banner.rotation = degreesRotated
+
+        if (splitBounds == null) {
+            // Single, fullscreen case
+            bannerParams.width = taskViewHeight - snapshotParams.topMargin
+            return Pair(translationX, snapshotParams.topMargin.toFloat())
+        }
+
+        // Set correct width and translations
+        val translationY: Float
+        if (desiredTaskId == splitBounds.leftTopTaskId) {
+            bannerParams.width = thumbnailViews[0].measuredHeight
+            translationY = snapshotParams.topMargin.toFloat()
+        } else {
+            bannerParams.width = thumbnailViews[1].measuredHeight
+            val topLeftTaskPlusDividerPercent =
+                if (splitBounds.appsStackedVertically) {
+                    splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
+                } else {
+                    splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
+                }
+            translationY =
+                snapshotParams.topMargin +
+                    (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+        }
+
+        return Pair(translationX, translationY)
+    }
+
+    /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
+    override val upDownSwipeDirection: SingleAxisSwipeDetector.Direction =
+        SingleAxisSwipeDetector.HORIZONTAL
+
+    override fun getUpDirection(isRtl: Boolean): Int =
+        if (isRtl) SingleAxisSwipeDetector.DIRECTION_NEGATIVE
+        else SingleAxisSwipeDetector.DIRECTION_POSITIVE
+
+    override fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean =
+        if (isRtl) displacement < 0 else displacement > 0
+
+    override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1
+    /* -------------------- */
+
+    override fun getChildBounds(
+        child: View,
+        childStart: Int,
+        pageCenter: Int,
+        layoutChild: Boolean
+    ): ChildBounds {
+        val childHeight = child.measuredHeight
+        val childWidth = child.measuredWidth
+        val childBottom = childStart + childHeight
+        val childLeft = pageCenter - childWidth / 2
+        if (layoutChild) {
+            child.layout(childLeft, childStart, childLeft + childWidth, childBottom)
+        }
+        return ChildBounds(childHeight, childWidth, childBottom, childLeft)
+    }
+
+    override fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int = rect.left
+
+    override fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption> =
+        // Add "left" side of phone which is actually the top
+        listOf(
+            SplitPositionOption(
+                R.drawable.ic_split_horizontal,
+                R.string.recent_task_option_split_screen,
+                STAGE_POSITION_TOP_OR_LEFT,
+                STAGE_TYPE_MAIN
+            )
+        )
+
+    override fun getInitialSplitPlaceholderBounds(
+        placeholderHeight: Int,
+        placeholderInset: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int,
+        out: Rect
+    ) {
+        // In fake land/seascape, the placeholder always needs to go to the "top" of the device,
+        // which is the same bounds as 0 rotation.
+        val width = dp.widthPx
+        val insetSizeAdjustment = getPlaceholderSizeAdjustment(dp)
+        out.set(0, 0, width, placeholderHeight + insetSizeAdjustment)
+        out.inset(placeholderInset, 0)
+
+        // Adjust the top to account for content off screen. This will help to animate the view in
+        // with rounded corners.
+        val screenWidth = dp.widthPx
+        val screenHeight = dp.heightPx
+        val totalHeight =
+            (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset) / screenWidth).toInt()
+        out.top -= totalHeight - placeholderHeight
+    }
+
+    override fun updateSplitIconParams(
+        out: View,
+        onScreenRectCenterX: Float,
+        onScreenRectCenterY: Float,
+        fullscreenScaleX: Float,
+        fullscreenScaleY: Float,
+        drawableWidth: Int,
+        drawableHeight: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int
+    ) {
+        val insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f
+        out.x = (onScreenRectCenterX / fullscreenScaleX - 1.0f * drawableWidth / 2)
+        out.y =
+            ((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY - 1.0f * drawableHeight / 2)
+    }
+
+    /**
+     * The split placeholder comes with a default inset to buffer the icon from the top of the
+     * screen. But if the device already has a large inset (from cutouts etc), use that instead.
+     */
+    private fun getPlaceholderSizeAdjustment(dp: DeviceProfile?): Int =
+        max((dp!!.insets.top - dp.splitPlaceholderInset).toDouble(), 0.0).toInt()
+
+    override fun setSplitInstructionsParams(
+        out: View,
+        dp: DeviceProfile,
+        splitInstructionsHeight: Int,
+        splitInstructionsWidth: Int
+    ) {
+        out.pivotX = 0f
+        out.pivotY = splitInstructionsHeight.toFloat()
+        out.rotation = degreesRotated
+        val distanceToEdge =
+            out.resources.getDimensionPixelSize(
+                R.dimen.split_instructions_bottom_margin_phone_landscape
+            )
+        // Adjust for any insets on the left edge
+        val insetCorrectionX = dp.insets.left
+        // Center the view in case of unbalanced insets on top or bottom of screen
+        val insetCorrectionY = (dp.insets.bottom - dp.insets.top) / 2
+        out.translationX = (distanceToEdge - insetCorrectionX).toFloat()
+        out.translationY =
+            (-splitInstructionsHeight - splitInstructionsWidth) / 2f + insetCorrectionY
+        // Setting gravity to LEFT instead of the lint-recommended START because we always want this
+        // view to be screen-left when phone is in landscape, regardless of the RtL setting.
+        val lp = out.layoutParams as FrameLayout.LayoutParams
+        lp.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
+        out.layoutParams = lp
+    }
+
+    override fun getFinalSplitPlaceholderBounds(
+        splitDividerSize: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int,
+        out1: Rect,
+        out2: Rect
+    ) {
+        // In fake land/seascape, the window bounds are always top and bottom half
+        val screenHeight = dp.heightPx
+        val screenWidth = dp.widthPx
+        out1.set(0, 0, screenWidth, screenHeight / 2 - splitDividerSize)
+        out2.set(0, screenHeight / 2 + splitDividerSize, screenWidth, screenHeight)
+    }
+
+    override fun setSplitTaskSwipeRect(
+        dp: DeviceProfile,
+        outRect: Rect,
+        splitInfo: SplitBounds,
+        desiredStagePosition: Int
+    ) {
+        val topLeftTaskPercent: Float
+        val dividerBarPercent: Float
+        if (splitInfo.appsStackedVertically) {
+            topLeftTaskPercent = splitInfo.topTaskPercent
+            dividerBarPercent = splitInfo.dividerHeightPercent
+        } else {
+            topLeftTaskPercent = splitInfo.leftTaskPercent
+            dividerBarPercent = splitInfo.dividerWidthPercent
+        }
+
+        if (desiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+            outRect.bottom = outRect.top + (outRect.height() * topLeftTaskPercent).toInt()
+        } else {
+            outRect.top += (outRect.height() * (topLeftTaskPercent + dividerBarPercent)).toInt()
+        }
+    }
+
+    override fun measureGroupedTaskViewThumbnailBounds(
+        primarySnapshot: View,
+        secondarySnapshot: View,
+        parentWidth: Int,
+        parentHeight: Int,
+        splitBoundsConfig: SplitBounds,
+        dp: DeviceProfile,
+        isRtl: Boolean
+    ) {
+        val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
+        val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
+
+        // Swap the margins that are set in TaskView#setRecentsOrientedState()
+        secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx
+        primaryParams.topMargin = 0
+
+        // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+        // (portrait bottom) and secondary is on the right (portrait top)
+        val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+        val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+        val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+        val (taskViewFirst, taskViewSecond) =
+            getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight)
+
+        primarySnapshot.translationY = spaceAboveSnapshot.toFloat()
+        primarySnapshot.measure(
+            MeasureSpec.makeMeasureSpec(taskViewFirst.x, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(taskViewFirst.y, MeasureSpec.EXACTLY)
+        )
+        val translationY = taskViewFirst.y + spaceAboveSnapshot + dividerBar
+        secondarySnapshot.translationY = (translationY - spaceAboveSnapshot).toFloat()
+        secondarySnapshot.measure(
+            MeasureSpec.makeMeasureSpec(taskViewSecond.x, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(taskViewSecond.y, MeasureSpec.EXACTLY)
+        )
+    }
+
+    override fun getGroupedTaskViewSizes(
+        dp: DeviceProfile,
+        splitBoundsConfig: SplitBounds,
+        parentWidth: Int,
+        parentHeight: Int
+    ): Pair<Point, Point> {
+        val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+        val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+        val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+        val taskPercent =
+            if (splitBoundsConfig.appsStackedVertically) {
+                splitBoundsConfig.topTaskPercent
+            } else {
+                splitBoundsConfig.leftTaskPercent
+            }
+        val firstTaskViewSize = Point(parentWidth, (totalThumbnailHeight * taskPercent).toInt())
+        val secondTaskViewSize =
+            Point(parentWidth, totalThumbnailHeight - firstTaskViewSize.y - dividerBar)
+        return Pair(firstTaskViewSize, secondTaskViewSize)
+    }
+
+    override fun setTaskIconParams(
+        iconParams: FrameLayout.LayoutParams,
+        taskIconMargin: Int,
+        taskIconHeight: Int,
+        thumbnailTopMargin: Int,
+        isRtl: Boolean
+    ) {
+        iconParams.gravity =
+            if (isRtl) {
+                Gravity.START or Gravity.CENTER_VERTICAL
+            } else {
+                Gravity.END or Gravity.CENTER_VERTICAL
+            }
+        iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2
+        iconParams.leftMargin = 0
+        iconParams.topMargin = thumbnailTopMargin / 2
+        iconParams.bottomMargin = 0
+    }
+
+    override fun setIconAppChipChildrenParams(
+        iconParams: FrameLayout.LayoutParams,
+        chipChildMarginStart: Int
+    ) {
+        iconParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+        iconParams.marginStart = chipChildMarginStart
+        iconParams.topMargin = 0
+    }
+
+    override fun setIconAppChipMenuParams(
+        iconAppChipView: IconAppChipView,
+        iconMenuParams: FrameLayout.LayoutParams,
+        iconMenuMargin: Int,
+        thumbnailTopMargin: Int
+    ) {
+        val isRtl = iconAppChipView.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
+        if (isRtl) {
+            iconMenuParams.gravity = Gravity.START or Gravity.BOTTOM
+            iconMenuParams.marginStart = iconMenuMargin
+            iconMenuParams.bottomMargin = iconMenuMargin
+            iconAppChipView.pivotX = iconMenuParams.width - iconMenuParams.height / 2f
+            iconAppChipView.pivotY = iconMenuParams.height / 2f
+        } else {
+            iconMenuParams.gravity = Gravity.END or Gravity.TOP
+            iconMenuParams.marginStart = 0
+            iconMenuParams.bottomMargin = 0
+            iconAppChipView.pivotX = iconMenuParams.width / 2f
+            iconAppChipView.pivotY = iconMenuParams.width / 2f
+        }
+
+        iconMenuParams.topMargin = iconMenuMargin
+        iconMenuParams.marginEnd = iconMenuMargin
+        iconAppChipView.setSplitTranslationY(0f)
+        iconAppChipView.setRotation(degreesRotated)
+    }
+
+    override fun setSplitIconParams(
+        primaryIconView: View,
+        secondaryIconView: View,
+        taskIconHeight: Int,
+        primarySnapshotWidth: Int,
+        primarySnapshotHeight: Int,
+        groupedTaskViewHeight: Int,
+        groupedTaskViewWidth: Int,
+        isRtl: Boolean,
+        deviceProfile: DeviceProfile,
+        splitConfig: SplitBounds
+    ) {
+        val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx
+        val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot
+        val dividerBar: Int = getDividerBarSize(totalThumbnailHeight, splitConfig)
+
+        val (topLeftY, bottomRightY) =
+            getSplitIconsPosition(
+                taskIconHeight,
+                primarySnapshotHeight,
+                totalThumbnailHeight,
+                isRtl,
+                deviceProfile.overviewTaskMarginPx,
+                dividerBar
+            )
+
+        updateSplitIconsPosition(primaryIconView, topLeftY, isRtl)
+        updateSplitIconsPosition(secondaryIconView, bottomRightY, isRtl)
+    }
+
+    override fun getDefaultSplitPosition(deviceProfile: DeviceProfile): Int {
+        throw IllegalStateException("Default position not available in fake landscape")
+    }
+
+    override fun <T> getSplitSelectTaskOffset(
+        primary: FloatProperty<T>,
+        secondary: FloatProperty<T>,
+        deviceProfile: DeviceProfile
+    ): Pair<FloatProperty<T>, FloatProperty<T>> = Pair(primary, secondary)
+
+    override fun getFloatingTaskOffscreenTranslationTarget(
+        floatingTask: View,
+        onScreenRect: RectF,
+        @StagePosition stagePosition: Int,
+        dp: DeviceProfile
+    ): Float = floatingTask.translationY - onScreenRect.height()
+
+    override fun setFloatingTaskPrimaryTranslation(
+        floatingTask: View,
+        translation: Float,
+        dp: DeviceProfile
+    ) {
+        floatingTask.translationY = translation
+    }
+
+    override fun getFloatingTaskPrimaryTranslation(floatingTask: View, dp: DeviceProfile): Float =
+        floatingTask.translationY
+
+    /**
+     * Retrieves split icons position
+     *
+     * @param taskIconHeight The height of the task icon.
+     * @param primarySnapshotHeight The height for the primary snapshot (i.e., top-left snapshot).
+     * @param totalThumbnailHeight The total height for the group task view.
+     * @param isRtl Whether the layout direction is RTL (or false for LTR).
+     * @param overviewTaskMarginPx The space under the focused task icon provided by Device Profile.
+     * @param dividerSize The size of the divider for the group task view.
+     * @return The top-left and right-bottom positions for the icon views.
+     */
+    @VisibleForTesting
+    open fun getSplitIconsPosition(
+        taskIconHeight: Int,
+        primarySnapshotHeight: Int,
+        totalThumbnailHeight: Int,
+        isRtl: Boolean,
+        overviewTaskMarginPx: Int,
+        dividerSize: Int,
+    ): SplitIconPositions {
+        return if (Flags.enableOverviewIconMenu()) {
+            if (isRtl) {
+                SplitIconPositions(0, -(totalThumbnailHeight - primarySnapshotHeight))
+            } else {
+                SplitIconPositions(0, primarySnapshotHeight + dividerSize)
+            }
+        } else {
+            val topLeftY = primarySnapshotHeight + overviewTaskMarginPx
+            SplitIconPositions(
+                topLeftY = topLeftY,
+                bottomRightY = topLeftY + dividerSize + taskIconHeight
+            )
+        }
+    }
+
+    /**
+     * Updates icon view gravity and translation for split tasks
+     *
+     * @param iconView View to be updated
+     * @param translationY the translationY that should be applied
+     * @param isRtl Whether the layout direction is RTL (or false for LTR).
+     */
+    @SuppressLint("RtlHardcoded")
+    @VisibleForTesting
+    open fun updateSplitIconsPosition(iconView: View, translationY: Int, isRtl: Boolean) {
+        val layoutParams = iconView.layoutParams as FrameLayout.LayoutParams
+
+        if (Flags.enableOverviewIconMenu()) {
+            val appChipView = iconView as IconAppChipView
+            layoutParams.gravity =
+                if (isRtl) Gravity.BOTTOM or Gravity.START else Gravity.TOP or Gravity.END
+            appChipView.layoutParams = layoutParams
+            appChipView.setSplitTranslationX(0f)
+            appChipView.setSplitTranslationY(translationY.toFloat())
+        } else {
+            layoutParams.gravity = Gravity.TOP or Gravity.RIGHT
+            layoutParams.topMargin = translationY
+            iconView.translationX = 0f
+            iconView.translationY = 0f
+            iconView.layoutParams = layoutParams
+        }
+    }
+
+    /**
+     * It calculates the divider's size in the group task view.
+     *
+     * @param totalThumbnailHeight The total height for the group task view
+     * @param splitConfig Contains information about sizes and proportions for split task.
+     * @return The divider size for the group task view.
+     */
+    protected fun getDividerBarSize(totalThumbnailHeight: Int, splitConfig: SplitBounds): Int {
+        return Math.round(
+            totalThumbnailHeight *
+                if (splitConfig.appsStackedVertically) splitConfig.dividerHeightPercent
+                else splitConfig.dividerWidthPercent
+        )
+    }
+
+    /**
+     * Data structure to keep the y position to be used for the split task icon views translation.
+     *
+     * @param topLeftY The y-axis position for the task view position on the Top or Left side.
+     * @param bottomRightY The y-axis position for the task view position on the Bottom or Right
+     *   side.
+     */
+    data class SplitIconPositions(val topLeftY: Int, val bottomRightY: Int)
+}
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
similarity index 84%
rename from src/com/android/launcher3/touch/PortraitPagedViewHandler.java
rename to quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index 04b6710..1be908b 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.launcher3.touch;
+package com.android.quickstep.orientation;
 
 import static android.view.Gravity.BOTTOM;
 import static android.view.Gravity.CENTER_HORIZONTAL;
 import static android.view.Gravity.END;
 import static android.view.Gravity.START;
 import static android.view.Gravity.TOP;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
@@ -33,8 +32,8 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
 
-import android.content.res.Resources;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -42,26 +41,27 @@
 import android.util.FloatProperty;
 import android.util.Pair;
 import android.view.Gravity;
-import android.view.MotionEvent;
 import android.view.Surface;
-import android.view.VelocityTracker;
 import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.touch.DefaultPagedViewHandler;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.quickstep.views.IconAppChipView;
 
 import java.util.ArrayList;
 import java.util.List;
 
-public class PortraitPagedViewHandler implements PagedOrientationHandler {
+public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements
+        RecentsPagedOrientationHandler {
 
     private final Matrix mTmpMatrix = new Matrix();
     private final RectF mTmpRectF = new RectF();
@@ -77,26 +77,6 @@
     }
 
     @Override
-    public int getPrimaryValue(int x, int y) {
-        return x;
-    }
-
-    @Override
-    public int getSecondaryValue(int x, int y) {
-        return y;
-    }
-
-    @Override
-    public float getPrimaryValue(float x, float y) {
-        return x;
-    }
-
-    @Override
-    public float getSecondaryValue(float x, float y) {
-        return y;
-    }
-
-    @Override
     public boolean isLayoutNaturalToLauncher() {
         return true;
     }
@@ -116,16 +96,6 @@
     }
 
     @Override
-    public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
-        action.call(target, param, 0);
-    }
-
-    @Override
-    public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
-        action.call(target, param, 0);
-    }
-
-    @Override
     public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
         action.call(target, 0, param);
     }
@@ -137,21 +107,6 @@
     }
 
     @Override
-    public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
-        return event.getX(pointerIndex);
-    }
-
-    @Override
-    public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
-        return velocityTracker.getXVelocity(pointerId);
-    }
-
-    @Override
-    public int getMeasuredSize(View view) {
-        return view.getMeasuredWidth();
-    }
-
-    @Override
     public int getPrimarySize(View view) {
         return view.getWidth();
     }
@@ -192,26 +147,6 @@
     }
 
     @Override
-    public int getPrimaryScroll(View view) {
-        return view.getScrollX();
-    }
-
-    @Override
-    public float getPrimaryScale(View view) {
-        return view.getScaleX();
-    }
-
-    @Override
-    public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
-        event.setMaxScrollX(maxScroll);
-    }
-
-    @Override
-    public boolean getRecentsRtlSetting(Resources resources) {
-        return !Utilities.isRtl(resources);
-    }
-
-    @Override
     public float getDegreesRotated() {
         return 0;
     }
@@ -231,27 +166,6 @@
         view.setScaleY(scale);
     }
 
-    @Override
-    public int getChildStart(View view) {
-        return view.getLeft();
-    }
-
-    @Override
-    public int getCenterForPage(View view, Rect insets) {
-        return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
-            - insets.bottom - view.getPaddingBottom()) / 2;
-    }
-
-    @Override
-    public int getScrollOffsetStart(View view, Rect insets) {
-        return insets.left + view.getPaddingLeft();
-    }
-
-    @Override
-    public int getScrollOffsetEnd(View view, Rect insets) {
-        return view.getWidth() - view.getPaddingRight() - insets.right;
-    }
-
     public int getSecondaryTranslationDirectionFactor() {
         return -1;
     }
@@ -268,12 +182,7 @@
     @Override
     public float getTaskMenuX(float x, View thumbnailView,
             DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            if (thumbnailView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                return x + taskInsetMargin - taskViewIcon.getHeight() - (taskInsetMargin / 2f);
-            }
-            return x + taskInsetMargin;
-        } else if (deviceProfile.isLandscape) {
+        if (deviceProfile.isLandscape) {
             return x + taskInsetMargin
                     + (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
         } else {
@@ -284,9 +193,6 @@
     @Override
     public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
             View taskMenuView, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            return y;
-        }
         return y + taskInsetMargin;
     }
 
@@ -295,7 +201,7 @@
             @StagePosition int stagePosition) {
         if (enableOverviewIconMenu()) {
             return thumbnailView.getResources().getDimensionPixelSize(
-                    R.dimen.task_thumbnail_icon_menu_max_width);
+                    R.dimen.task_thumbnail_icon_menu_expanded_width);
         }
         int padding = thumbnailView.getResources()
                 .getDimensionPixelSize(R.dimen.task_menu_edge_padding);
@@ -305,6 +211,13 @@
     }
 
     @Override
+    public int getTaskMenuHeight(float taskInsetMargin, DeviceProfile deviceProfile,
+            float taskMenuX, float taskMenuY) {
+        return (int) (deviceProfile.heightPx - deviceProfile.getInsets().top - taskMenuY
+                    - deviceProfile.getOverviewActionsClaimedSpaceBelow());
+    }
+
+    @Override
     public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
             LinearLayout taskMenuLayout, int dividerSpacing,
             ShapeDrawable dividerDrawable) {
@@ -400,20 +313,6 @@
     }
 
     /* -------------------- */
-
-    @Override
-    public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
-        boolean layoutChild) {
-        final int childWidth = child.getMeasuredWidth();
-        final int childRight = childStart + childWidth;
-        final int childHeight = child.getMeasuredHeight();
-        final int childTop = pageCenter - childHeight / 2;
-        if (layoutChild) {
-            child.layout(childStart, childTop, childRight, childTop + childHeight);
-        }
-        return new ChildBounds(childWidth, childHeight, childRight, childTop);
-    }
-
     @Override
     public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
         return dp.heightPx - rect.bottom;
@@ -631,24 +530,16 @@
         float dividerScale = splitBoundsConfig.appsStackedVertically
                 ? splitBoundsConfig.dividerHeightPercent
                 : splitBoundsConfig.dividerWidthPercent;
-        int primarySnapshotHeight;
-        int primarySnapshotWidth;
-        int secondarySnapshotHeight;
-        int secondarySnapshotWidth;
-        float taskPercent = splitBoundsConfig.appsStackedVertically ?
-                splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent;
+        Pair<Point, Point> taskViewSizes =
+                getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight);
         if (dp.isLeftRightSplit) {
             int scaledDividerBar = Math.round(parentWidth * dividerScale);
-            primarySnapshotHeight = totalThumbnailHeight;
-            primarySnapshotWidth = Math.round(parentWidth * taskPercent);
-
-            secondarySnapshotHeight = totalThumbnailHeight;
-            secondarySnapshotWidth = parentWidth - primarySnapshotWidth - scaledDividerBar;
-            int translationX = primarySnapshotWidth + scaledDividerBar;
             if (isRtl) {
+                int translationX = taskViewSizes.second.x + scaledDividerBar;
                 primarySnapshot.setTranslationX(-translationX);
                 secondarySnapshot.setTranslationX(0);
             } else {
+                int translationX = taskViewSizes.first.x + scaledDividerBar;
                 secondarySnapshot.setTranslationX(translationX);
                 primarySnapshot.setTranslationX(0);
             }
@@ -657,18 +548,8 @@
             // Reset unused translations
             primarySnapshot.setTranslationY(0);
         } else {
-            int taskbarHeight = dp.isTransientTaskbar ? 0 : dp.taskbarHeight;
-            float scale = (float) totalThumbnailHeight / (dp.availableHeightPx - taskbarHeight);
-            float topTaskHeight = dp.availableHeightPx * taskPercent;
             float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
-            float scaledTopTaskHeight = topTaskHeight * scale;
-            primarySnapshotWidth = parentWidth;
-            primarySnapshotHeight = Math.round(scaledTopTaskHeight);
-
-            secondarySnapshotWidth = parentWidth;
-            secondarySnapshotHeight = Math.round(totalThumbnailHeight - primarySnapshotHeight
-                    - finalDividerHeight);
-            float translationY = primarySnapshotHeight + spaceAboveSnapshot + finalDividerHeight;
+            float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
             secondarySnapshot.setTranslationY(translationY);
 
             FrameLayout.LayoutParams primaryParams =
@@ -684,11 +565,11 @@
             primarySnapshot.setTranslationX(0);
         }
         primarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
+                View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY));
         secondarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
+                View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y,
                         View.MeasureSpec.EXACTLY));
         primarySnapshot.setScaleX(1);
         secondarySnapshot.setScaleX(1);
@@ -697,14 +578,50 @@
     }
 
     @Override
+    public Pair<Point, Point> getGroupedTaskViewSizes(
+            DeviceProfile dp,
+            SplitBounds splitBoundsConfig,
+            int parentWidth,
+            int parentHeight) {
+        int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
+        int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
+        float dividerScale = splitBoundsConfig.appsStackedVertically
+                ? splitBoundsConfig.dividerHeightPercent
+                : splitBoundsConfig.dividerWidthPercent;
+        float taskPercent = splitBoundsConfig.appsStackedVertically
+                ? splitBoundsConfig.topTaskPercent
+                : splitBoundsConfig.leftTaskPercent;
+
+        Point firstTaskViewSize = new Point();
+        Point secondTaskViewSize = new Point();
+
+        if (dp.isLeftRightSplit) {
+            int scaledDividerBar = Math.round(parentWidth * dividerScale);
+            firstTaskViewSize.x = Math.round(parentWidth * taskPercent);
+            firstTaskViewSize.y = totalThumbnailHeight;
+
+            secondTaskViewSize.x = parentWidth - firstTaskViewSize.x - scaledDividerBar;
+            secondTaskViewSize.y = totalThumbnailHeight;
+        } else {
+            int taskbarHeight = dp.isTransientTaskbar ? 0 : dp.taskbarHeight;
+            float scale = (float) totalThumbnailHeight / (dp.availableHeightPx - taskbarHeight);
+            float topTaskHeight = dp.availableHeightPx * taskPercent;
+            float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
+            float scaledTopTaskHeight = topTaskHeight * scale;
+            firstTaskViewSize.x = parentWidth;
+            firstTaskViewSize.y = Math.round(scaledTopTaskHeight);
+
+            secondTaskViewSize.x = parentWidth;
+            secondTaskViewSize.y = Math.round(totalThumbnailHeight - firstTaskViewSize.y
+                    - finalDividerHeight);
+        }
+
+        return new Pair<>(firstTaskViewSize, secondTaskViewSize);
+    }
+
+    @Override
     public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
             int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
-        if (enableOverviewIconMenu()) {
-            iconParams.setMarginStart(taskIconMargin);
-            iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
-            iconParams.topMargin = 0;
-            return;
-        }
         iconParams.gravity = TOP | CENTER_HORIZONTAL;
         // Reset margins, since they may have been set on rotation
         iconParams.leftMargin = iconParams.rightMargin = 0;
@@ -712,7 +629,15 @@
     }
 
     @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
+    public void setIconAppChipChildrenParams(FrameLayout.LayoutParams iconParams,
+            int chipChildMarginStart) {
+        iconParams.setMarginStart(chipChildMarginStart);
+        iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
+        iconParams.topMargin = 0;
+    }
+
+    @Override
+    public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
             FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
         iconMenuParams.gravity = TOP | START;
         iconMenuParams.setMarginStart(iconMenuMargin);
@@ -720,10 +645,10 @@
         iconMenuParams.bottomMargin = 0;
         iconMenuParams.setMarginEnd(0);
 
-        iconAppChipMenuView.setPivotX(0);
-        iconAppChipMenuView.setPivotY(0);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
+        iconAppChipView.setPivotX(0);
+        iconAppChipView.setPivotY(0);
+        iconAppChipView.setSplitTranslationY(0);
+        iconAppChipView.setRotation(getDegreesRotated());
     }
 
     @Override
@@ -738,22 +663,25 @@
                 : new FrameLayout.LayoutParams(primaryIconParams);
 
         if (enableOverviewIconMenu()) {
+            IconAppChipView primaryAppChipView = (IconAppChipView) primaryIconView;
+            IconAppChipView secondaryAppChipView = (IconAppChipView) secondaryIconView;
             primaryIconParams.gravity = TOP | START;
             secondaryIconParams.gravity = TOP | START;
             secondaryIconParams.topMargin = primaryIconParams.topMargin;
             secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart());
             if (deviceProfile.isLeftRightSplit) {
                 if (isRtl) {
-                    primaryIconView.setTranslationX(-primarySnapshotWidth);
+                    int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth;
+                    primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth);
                 } else {
-                    secondaryIconView.setTranslationX(primarySnapshotWidth);
+                    secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth);
                 }
             } else {
-                primaryIconView.setTranslationX(0);
-                secondaryIconView.setTranslationX(0);
+                primaryAppChipView.setSplitTranslationX(0);
+                secondaryAppChipView.setSplitTranslationX(0);
                 int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
                         splitConfig.visualDividerBounds.height());
-                secondaryIconView.setTranslationY(
+                secondaryAppChipView.setSplitTranslationY(
                         primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness));
             }
         } else if (deviceProfile.isLeftRightSplit) {
@@ -869,7 +797,7 @@
     }
 
     @Override
-    public Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
+    public float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
         return dp.isLeftRightSplit
                 ? floatingTask.getTranslationX()
                 : floatingTask.getTranslationY();
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
new file mode 100644
index 0000000..6c82890
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.ShapeDrawable
+import android.util.FloatProperty
+import android.util.Pair
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.touch.PagedOrientationHandler
+import com.android.launcher3.touch.PagedOrientationHandler.Float2DAction
+import com.android.launcher3.touch.PagedOrientationHandler.Int2DAction
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.quickstep.views.IconAppChipView
+
+/**
+ * Abstraction layer to separate horizontal and vertical specific implementations for
+ * [com.android.quickstep.views.RecentsView]. Majority of these implementations are (should be) as
+ * simple as choosing the correct X and Y analogous methods.
+ */
+interface RecentsPagedOrientationHandler : PagedOrientationHandler {
+    fun <T> setSecondary(target: T, action: Float2DAction<T>, param: Float)
+
+    operator fun <T> set(target: T, action: Int2DAction<T>, primaryParam: Int, secondaryParam: Int)
+
+    fun getPrimarySize(view: View): Int
+
+    fun getPrimarySize(rect: RectF): Float
+
+    val secondaryTranslationDirectionFactor: Int
+
+    val degreesRotated: Float
+
+    val rotation: Int
+
+    val isLayoutNaturalToLauncher: Boolean
+
+    fun <T> getPrimaryValue(x: T, y: T): T
+
+    fun <T> getSecondaryValue(x: T, y: T): T
+
+    fun setPrimaryScale(view: View, scale: Float)
+
+    fun setSecondaryScale(view: View, scale: Float)
+
+    fun getStart(rect: RectF): Float
+
+    fun getEnd(rect: RectF): Float
+
+    fun getClearAllSidePadding(view: View, isRtl: Boolean): Int
+
+    fun getSecondaryDimension(view: View): Int
+
+    val primaryViewTranslate: FloatProperty<View>
+    val secondaryViewTranslate: FloatProperty<View>
+
+    fun getSplitTranslationDirectionFactor(
+        @StagePosition stagePosition: Int,
+        deviceProfile: DeviceProfile
+    ): Int
+
+    fun <T> getSplitSelectTaskOffset(
+        primary: FloatProperty<T>,
+        secondary: FloatProperty<T>,
+        deviceProfile: DeviceProfile
+    ): Pair<FloatProperty<T>, FloatProperty<T>>
+
+    fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int
+
+    fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption>
+
+    /** @param placeholderHeight height of placeholder view in portrait, width in landscape */
+    fun getInitialSplitPlaceholderBounds(
+        placeholderHeight: Int,
+        placeholderInset: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int,
+        out: Rect
+    )
+
+    /**
+     * Centers an icon in the split staging area, accounting for insets.
+     *
+     * @param out The icon that needs to be centered.
+     * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
+     *   offscreen).
+     * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
+     *   offscreen).
+     * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
+     * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
+     * @param drawableWidth The icon's drawable (final) width.
+     * @param drawableHeight The icon's drawable (final) height.
+     * @param dp The device profile, used to report rotation and hardware insets.
+     * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
+     */
+    fun updateSplitIconParams(
+        out: View,
+        onScreenRectCenterX: Float,
+        onScreenRectCenterY: Float,
+        fullscreenScaleX: Float,
+        fullscreenScaleY: Float,
+        drawableWidth: Int,
+        drawableHeight: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int
+    )
+
+    /**
+     * Sets positioning and rotation for a SplitInstructionsView.
+     *
+     * @param out The SplitInstructionsView that needs to be positioned.
+     * @param dp The device profile, used to report rotation and device type.
+     * @param splitInstructionsHeight The SplitInstructionView's height.
+     * @param splitInstructionsWidth The SplitInstructionView's width.
+     */
+    fun setSplitInstructionsParams(
+        out: View,
+        dp: DeviceProfile,
+        splitInstructionsHeight: Int,
+        splitInstructionsWidth: Int
+    )
+
+    /**
+     * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
+     * @param stagePosition the split position option (top/left, bottom/right) of the first task
+     *   selected for entering split
+     * @param out1 the bounds for where the first selected app will be
+     * @param out2 the bounds for where the second selected app will be, complimentary to {@param
+     *   out1} based on {@param initialSplitOption}
+     */
+    fun getFinalSplitPlaceholderBounds(
+        splitDividerSize: Int,
+        dp: DeviceProfile,
+        @StagePosition stagePosition: Int,
+        out1: Rect,
+        out2: Rect
+    )
+
+    fun getDefaultSplitPosition(deviceProfile: DeviceProfile): Int
+
+    /**
+     * @param outRect This is expected to be the rect that has the dimensions for a non-split,
+     *   fullscreen task in overview. This will directly be modified.
+     * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
+     *   outRect for
+     */
+    fun setSplitTaskSwipeRect(
+        dp: DeviceProfile,
+        outRect: Rect,
+        splitInfo: SplitConfigurationOptions.SplitBounds,
+        @StagePosition desiredStagePosition: Int
+    )
+
+    fun measureGroupedTaskViewThumbnailBounds(
+        primarySnapshot: View,
+        secondarySnapshot: View,
+        parentWidth: Int,
+        parentHeight: Int,
+        splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
+        dp: DeviceProfile,
+        isRtl: Boolean
+    )
+
+    /**
+     * Creates two Points representing the dimensions of the two tasks in a GroupedTaskView
+     *
+     * @return first -> primary task snapshot, second -> secondary task snapshot. x -> width, y ->
+     *   height
+     */
+    fun getGroupedTaskViewSizes(
+        dp: DeviceProfile,
+        splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
+        parentWidth: Int,
+        parentHeight: Int
+    ): Pair<Point, Point>
+    // Overview TaskMenuView methods
+    /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
+    fun setTaskIconParams(
+        iconParams: FrameLayout.LayoutParams,
+        taskIconMargin: Int,
+        taskIconHeight: Int,
+        thumbnailTopMargin: Int,
+        isRtl: Boolean
+    )
+
+    /**
+     * Sets layout params on the children of an app chip. Only use this when app chip is enabled.
+     */
+    fun setIconAppChipChildrenParams(
+        iconParams: FrameLayout.LayoutParams,
+        chipChildMarginStart: Int
+    )
+
+    fun setIconAppChipMenuParams(
+        iconAppChipView: IconAppChipView,
+        iconMenuParams: FrameLayout.LayoutParams,
+        iconMenuMargin: Int,
+        thumbnailTopMargin: Int
+    )
+
+    fun setSplitIconParams(
+        primaryIconView: View,
+        secondaryIconView: View,
+        taskIconHeight: Int,
+        primarySnapshotWidth: Int,
+        primarySnapshotHeight: Int,
+        groupedTaskViewHeight: Int,
+        groupedTaskViewWidth: Int,
+        isRtl: Boolean,
+        deviceProfile: DeviceProfile,
+        splitConfig: SplitConfigurationOptions.SplitBounds
+    )
+
+    /*
+     * The following two methods try to center the TaskMenuView in landscape by finding the center
+     * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
+     * taskMenu width is the same size as the thumbnail width (what got set below in
+     * getTaskMenuWidth()), so we directly use that in the calculations.
+     */
+    fun getTaskMenuX(
+        x: Float,
+        thumbnailView: View,
+        deviceProfile: DeviceProfile,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float
+
+    fun getTaskMenuY(
+        y: Float,
+        thumbnailView: View,
+        stagePosition: Int,
+        taskMenuView: View,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float
+
+    fun getTaskMenuWidth(
+        thumbnailView: View,
+        deviceProfile: DeviceProfile,
+        @StagePosition stagePosition: Int
+    ): Int
+
+    fun getTaskMenuHeight(
+        taskInsetMargin: Float,
+        deviceProfile: DeviceProfile,
+        taskMenuX: Float,
+        taskMenuY: Float
+    ): Int
+
+    /**
+     * Sets linear layout orientation for [com.android.launcher3.popup.SystemShortcut] items inside
+     * task menu view.
+     */
+    fun setTaskOptionsMenuLayoutOrientation(
+        deviceProfile: DeviceProfile,
+        taskMenuLayout: LinearLayout,
+        dividerSpacing: Int,
+        dividerDrawable: ShapeDrawable
+    )
+
+    /**
+     * Sets layout param attributes for [com.android.launcher3.popup.SystemShortcut] child views
+     * inside task menu view.
+     */
+    fun setLayoutParamsForTaskMenuOptionItem(
+        lp: LinearLayout.LayoutParams,
+        viewGroup: LinearLayout,
+        deviceProfile: DeviceProfile
+    )
+
+    /**
+     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+     * TaskView.
+     *
+     * @return A Pair of Floats representing the proper x and y translations.
+     */
+    fun getDwbLayoutTranslations(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        splitBounds: SplitConfigurationOptions.SplitBounds?,
+        deviceProfile: DeviceProfile,
+        thumbnailViews: Array<View>,
+        desiredTaskId: Int,
+        banner: View
+    ): Pair<Float, Float>
+    // The following are only used by TaskViewTouchHandler.
+
+    /** @return Either VERTICAL or HORIZONTAL. */
+    val upDownSwipeDirection: SingleAxisSwipeDetector.Direction
+
+    /** @return Given [.getUpDownSwipeDirection], whether POSITIVE or NEGATIVE is up. */
+    fun getUpDirection(isRtl: Boolean): Int
+
+    /** @return Whether the displacement is going towards the top of the screen. */
+    fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean
+
+    /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
+    fun getTaskDragDisplacementFactor(isRtl: Boolean): Int
+
+    /**
+     * Maps the velocity from the coordinate plane of the foreground app to that of Launcher's
+     * (which now will always be portrait)
+     */
+    fun adjustFloatingIconStartVelocity(velocity: PointF)
+
+    /**
+     * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
+     *
+     * @param outStartRect The start rect that will directly be modified
+     */
+    fun fixBoundsForHomeAnimStartRect(outStartRect: RectF, deviceProfile: DeviceProfile)
+
+    /**
+     * Determine the target translation for animating the FloatingTaskView out. This value could
+     * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
+     * docked.
+     *
+     * @param floatingTask The FloatingTaskView.
+     * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
+     * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
+     * @param dp The device profile.
+     * @return A float. When an animation translates the FloatingTaskView to this position, it will
+     *   appear to tuck away off the edge of the screen.
+     */
+    fun getFloatingTaskOffscreenTranslationTarget(
+        floatingTask: View,
+        onScreenRect: RectF,
+        @StagePosition stagePosition: Int,
+        dp: DeviceProfile
+    ): Float
+
+    /**
+     * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+     * either x or y), depending on how the view is oriented.
+     *
+     * @param floatingTask The FloatingTaskView to be translated.
+     * @param translation The target translation value.
+     * @param dp The current device profile.
+     */
+    fun setFloatingTaskPrimaryTranslation(floatingTask: View, translation: Float, dp: DeviceProfile)
+
+    /**
+     * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+     * either x or y), depending on how the view is oriented.
+     *
+     * @param floatingTask The FloatingTaskView in question.
+     * @param dp The current device profile.
+     * @return The current translation value.
+     */
+    fun getFloatingTaskPrimaryTranslation(floatingTask: View, dp: DeviceProfile): Float
+
+    companion object {
+        @JvmField val PORTRAIT: RecentsPagedOrientationHandler = PortraitPagedViewHandler()
+        @JvmField val LANDSCAPE: RecentsPagedOrientationHandler = LandscapePagedViewHandler()
+        @JvmField val SEASCAPE: RecentsPagedOrientationHandler = SeascapePagedViewHandler()
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
new file mode 100644
index 0000000..5bebf8c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.annotation.SuppressLint
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.util.Pair
+import android.view.Gravity
+import android.view.Surface
+import android.view.View
+import android.view.View.MeasureSpec
+import android.widget.FrameLayout
+import androidx.core.util.component1
+import androidx.core.util.component2
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Flags
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.views.IconAppChipView
+
+class SeascapePagedViewHandler : LandscapePagedViewHandler() {
+    override val secondaryTranslationDirectionFactor: Int = -1
+
+    override fun getSplitTranslationDirectionFactor(
+        stagePosition: Int,
+        deviceProfile: DeviceProfile
+    ): Int = if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) -1 else 1
+
+    override fun getRecentsRtlSetting(resources: Resources): Boolean = Utilities.isRtl(resources)
+
+    override val degreesRotated: Float = 270f
+
+    override val rotation: Int = Surface.ROTATION_270
+
+    override fun adjustFloatingIconStartVelocity(velocity: PointF) =
+        velocity.set(velocity.y, -velocity.x)
+
+    override fun getTaskMenuX(
+        x: Float,
+        thumbnailView: View,
+        deviceProfile: DeviceProfile,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float = x + taskInsetMargin
+
+    override fun getTaskMenuY(
+        y: Float,
+        thumbnailView: View,
+        stagePosition: Int,
+        taskMenuView: View,
+        taskInsetMargin: Float,
+        taskViewIcon: View
+    ): Float {
+        if (Flags.enableOverviewIconMenu()) {
+            return y
+        }
+        val lp = taskMenuView.layoutParams as BaseDragLayer.LayoutParams
+        val taskMenuWidth = lp.width
+        return if (stagePosition == STAGE_POSITION_UNDEFINED) {
+            y + taskInsetMargin + (thumbnailView.measuredHeight + taskMenuWidth) / 2f
+        } else {
+            y + taskMenuWidth + taskInsetMargin
+        }
+    }
+
+    override fun getTaskMenuHeight(
+        taskInsetMargin: Float,
+        deviceProfile: DeviceProfile,
+        taskMenuX: Float,
+        taskMenuY: Float
+    ): Int = (deviceProfile.availableWidthPx - taskInsetMargin - taskMenuX).toInt()
+
+    override fun setSplitTaskSwipeRect(
+        dp: DeviceProfile,
+        outRect: Rect,
+        splitInfo: SplitBounds,
+        desiredStagePosition: Int
+    ) {
+        val topLeftTaskPercent: Float
+        val dividerBarPercent: Float
+        if (splitInfo.appsStackedVertically) {
+            topLeftTaskPercent = splitInfo.topTaskPercent
+            dividerBarPercent = splitInfo.dividerHeightPercent
+        } else {
+            topLeftTaskPercent = splitInfo.leftTaskPercent
+            dividerBarPercent = splitInfo.dividerWidthPercent
+        }
+
+        // In seascape, the primary thumbnail is counterintuitively placed at the physical bottom of
+        // the screen. This is to preserve consistency when the user rotates: From the user's POV,
+        // the primary should always be on the left.
+        if (desiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+            outRect.top += (outRect.height() * (1 - topLeftTaskPercent)).toInt()
+        } else {
+            outRect.bottom -= (outRect.height() * (topLeftTaskPercent + dividerBarPercent)).toInt()
+        }
+    }
+
+    override fun getDwbLayoutTranslations(
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        splitBounds: SplitBounds?,
+        deviceProfile: DeviceProfile,
+        thumbnailViews: Array<View>,
+        desiredTaskId: Int,
+        banner: View
+    ): Pair<Float, Float> {
+        val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
+        val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
+        val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
+        bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START
+        banner.pivotX = 0f
+        banner.pivotY = 0f
+        banner.rotation = degreesRotated
+
+        val translationX: Float = (taskViewWidth - banner.height).toFloat()
+        if (splitBounds == null) {
+            // Single, fullscreen case
+            bannerParams.width = taskViewHeight - snapshotParams.topMargin
+            return Pair(translationX, banner.height.toFloat())
+        }
+
+        // Set correct width and translations
+        val translationY: Float
+        if (desiredTaskId == splitBounds.leftTopTaskId) {
+            bannerParams.width = thumbnailViews[0].measuredHeight
+            val bottomRightTaskPlusDividerPercent =
+                if (splitBounds.appsStackedVertically) {
+                    1f - splitBounds.topTaskPercent
+                } else {
+                    1f - splitBounds.leftTaskPercent
+                }
+            translationY =
+                banner.height -
+                    (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent
+        } else {
+            bannerParams.width = thumbnailViews[1].measuredHeight
+            translationY = banner.height.toFloat()
+        }
+
+        return Pair(translationX, translationY)
+    }
+
+    override fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int =
+        dp.widthPx - rect.right
+
+    override fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption> =
+        // Add "right" option which is actually the top
+        listOf(
+            SplitPositionOption(
+                R.drawable.ic_split_horizontal,
+                R.string.recent_task_option_split_screen,
+                STAGE_POSITION_BOTTOM_OR_RIGHT,
+                STAGE_TYPE_MAIN
+            )
+        )
+
+    override fun setSplitInstructionsParams(
+        out: View,
+        dp: DeviceProfile,
+        splitInstructionsHeight: Int,
+        splitInstructionsWidth: Int
+    ) {
+        out.pivotX = 0f
+        out.pivotY = splitInstructionsHeight.toFloat()
+        out.rotation = degreesRotated
+        val distanceToEdge =
+            out.resources.getDimensionPixelSize(
+                R.dimen.split_instructions_bottom_margin_phone_landscape
+            )
+        // Adjust for any insets on the right edge
+        val insetCorrectionX = dp.insets.right
+        // Center the view in case of unbalanced insets on top or bottom of screen
+        val insetCorrectionY = (dp.insets.bottom - dp.insets.top) / 2
+        out.translationX = (splitInstructionsWidth - distanceToEdge + insetCorrectionX).toFloat()
+        out.translationY =
+            (-splitInstructionsHeight + splitInstructionsWidth) / 2f + insetCorrectionY
+        // Setting gravity to RIGHT instead of the lint-recommended END because we always want this
+        // view to be screen-right when phone is in seascape, regardless of the RtL setting.
+        val lp = out.layoutParams as FrameLayout.LayoutParams
+        lp.gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
+        out.layoutParams = lp
+    }
+
+    override fun setTaskIconParams(
+        iconParams: FrameLayout.LayoutParams,
+        taskIconMargin: Int,
+        taskIconHeight: Int,
+        thumbnailTopMargin: Int,
+        isRtl: Boolean
+    ) {
+        iconParams.gravity =
+            if (isRtl) {
+                Gravity.END or Gravity.CENTER_VERTICAL
+            } else {
+                Gravity.START or Gravity.CENTER_VERTICAL
+            }
+        iconParams.setMargins(-taskIconHeight - taskIconMargin / 2, thumbnailTopMargin / 2, 0, 0)
+    }
+
+    override fun setIconAppChipChildrenParams(
+        iconParams: FrameLayout.LayoutParams,
+        chipChildMarginStart: Int
+    ) {
+        iconParams.setMargins(0, 0, 0, 0)
+        iconParams.marginStart = chipChildMarginStart
+        iconParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+    }
+
+    override fun setIconAppChipMenuParams(
+        iconAppChipView: IconAppChipView,
+        iconMenuParams: FrameLayout.LayoutParams,
+        iconMenuMargin: Int,
+        thumbnailTopMargin: Int
+    ) {
+        val isRtl = iconAppChipView.layoutDirection == View.LAYOUT_DIRECTION_RTL
+        val iconCenter = iconAppChipView.getHeight() / 2f
+
+        if (isRtl) {
+            iconMenuParams.gravity = Gravity.TOP or Gravity.END
+            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.topMargin = 0
+            iconMenuParams.marginEnd = 0
+            iconAppChipView.pivotX = iconCenter
+            iconAppChipView.pivotY = iconCenter - iconMenuMargin
+        }
+        iconMenuParams.marginStart = 0
+        iconMenuParams.bottomMargin = 0
+        iconAppChipView.setSplitTranslationY(0f)
+        iconAppChipView.setRotation(degreesRotated)
+    }
+
+    override fun measureGroupedTaskViewThumbnailBounds(
+        primarySnapshot: View,
+        secondarySnapshot: View,
+        parentWidth: Int,
+        parentHeight: Int,
+        splitBoundsConfig: SplitBounds,
+        dp: DeviceProfile,
+        isRtl: Boolean
+    ) {
+        val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
+        val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
+
+        // Swap the margins that are set in TaskView#setRecentsOrientedState()
+        secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx
+        primaryParams.topMargin = 0
+
+        // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+        // (portrait bottom) and secondary is on the right (portrait top)
+        val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+        val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+        val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+        val (taskViewFirst, taskViewSecond) =
+            getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight)
+        secondarySnapshot.translationY = 0f
+        primarySnapshot.translationY =
+            (taskViewSecond.y + spaceAboveSnapshot + dividerBar).toFloat()
+        primarySnapshot.measure(
+            MeasureSpec.makeMeasureSpec(taskViewFirst.x, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(taskViewFirst.y, MeasureSpec.EXACTLY)
+        )
+        secondarySnapshot.measure(
+            MeasureSpec.makeMeasureSpec(taskViewSecond.x, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(taskViewSecond.y, MeasureSpec.EXACTLY)
+        )
+    }
+
+    override fun getGroupedTaskViewSizes(
+        dp: DeviceProfile,
+        splitBoundsConfig: SplitBounds,
+        parentWidth: Int,
+        parentHeight: Int
+    ): Pair<Point, Point> {
+        // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+        // (portrait bottom) and secondary is on the right (portrait top)
+        val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+        val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+        val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+        val taskPercent =
+            if (splitBoundsConfig.appsStackedVertically) {
+                splitBoundsConfig.topTaskPercent
+            } else {
+                splitBoundsConfig.leftTaskPercent
+            }
+        val firstTaskViewSize = Point(parentWidth, (totalThumbnailHeight * taskPercent).toInt())
+        val secondTaskViewSize =
+            Point(parentWidth, totalThumbnailHeight - firstTaskViewSize.y - dividerBar)
+        return Pair(firstTaskViewSize, secondTaskViewSize)
+    }
+
+    /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
+    override val upDownSwipeDirection: SingleAxisSwipeDetector.Direction =
+        SingleAxisSwipeDetector.HORIZONTAL
+
+    override fun getUpDirection(isRtl: Boolean): Int =
+        if (isRtl) SingleAxisSwipeDetector.DIRECTION_POSITIVE
+        else SingleAxisSwipeDetector.DIRECTION_NEGATIVE
+
+    override fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean =
+        if (isRtl) displacement > 0 else displacement < 0
+
+    override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1
+    /* -------------------- */
+
+    override fun getSplitIconsPosition(
+        taskIconHeight: Int,
+        primarySnapshotHeight: Int,
+        totalThumbnailHeight: Int,
+        isRtl: Boolean,
+        overviewTaskMarginPx: Int,
+        dividerSize: Int,
+    ): SplitIconPositions {
+        return if (Flags.enableOverviewIconMenu()) {
+            if (isRtl) {
+                SplitIconPositions(
+                    topLeftY = totalThumbnailHeight - primarySnapshotHeight,
+                    bottomRightY = 0
+                )
+            } else {
+                SplitIconPositions(
+                    topLeftY = 0,
+                    bottomRightY = -(primarySnapshotHeight + dividerSize)
+                )
+            }
+        } else {
+            // In seascape, the icons are initially placed at the bottom start of the
+            // display (portrait locked). The values defined here are used to translate the icons
+            // from the bottom to the almost-center of the screen using the bottom margin.
+            // The primary snapshot is placed at the bottom, thus we translate the icons using
+            // the size of the primary snapshot minus the icon size for the top-left icon.
+            SplitIconPositions(
+                topLeftY = primarySnapshotHeight - taskIconHeight,
+                bottomRightY = primarySnapshotHeight + dividerSize
+            )
+        }
+    }
+
+    /**
+     * Updates icon view gravity and translation for split tasks
+     *
+     * @param iconView View to be updated
+     * @param translationY the translationY that should be applied
+     * @param isRtl Whether the layout direction is RTL (or false for LTR).
+     */
+    @SuppressLint("RtlHardcoded")
+    override fun updateSplitIconsPosition(iconView: View, translationY: Int, isRtl: Boolean) {
+        val layoutParams = iconView.layoutParams as FrameLayout.LayoutParams
+
+        if (Flags.enableOverviewIconMenu()) {
+            val appChipView = iconView as IconAppChipView
+            layoutParams.gravity =
+                if (isRtl) Gravity.TOP or Gravity.END else Gravity.BOTTOM or Gravity.START
+            appChipView.layoutParams = layoutParams
+            appChipView.setSplitTranslationX(0f)
+            appChipView.setSplitTranslationY(translationY.toFloat())
+        } else {
+            layoutParams.gravity = Gravity.BOTTOM or Gravity.LEFT
+            iconView.translationX = 0f
+            iconView.translationY = 0f
+            layoutParams.bottomMargin = translationY
+            iconView.layoutParams = layoutParams
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
index 4359294..cfa6b98 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java
@@ -39,7 +39,7 @@
         SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT,
         SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
         FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED, RECENT_TASKS_MISSING,
-        INVALID_VELOCITY_ON_SWIPE_UP,
+        INVALID_VELOCITY_ON_SWIPE_UP, RECENTS_ANIMATION_START_PENDING,
 
         /**
          * These GestureEvents are specifically associated to state flags that get set in
@@ -273,6 +273,15 @@
                 case START_RECENTS_ANIMATION:
                     lastStartRecentAnimationEventEntryTime = eventEntry.getTime();
                     break;
+                case RECENTS_ANIMATION_START_PENDING:
+                    errorDetected |= printErrorIfTrue(
+                            true,
+                            prefix,
+                            /* errorMessage= */ (eventEntry.getDuplicateCount() + 1)
+                                    + " gesture(s) attempted while a requested recents"
+                                    + " animation is still pending.",
+                            writer);
+                    break;
                 case EXPECTING_TASK_APPEARED:
                 case MOTION_DOWN:
                 case SET_END_TARGET:
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 278ca56..c54862a 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -67,15 +67,15 @@
     /**
      * Adds a log to be printed at log-dump-time.
      */
-    public void addLog(String event) {
+    public void addLog(@NonNull String event) {
         addLog(event, null);
     }
 
-    public void addLog(String event, int extras) {
+    public void addLog(@NonNull String event, int extras) {
         addLog(event, extras, null);
     }
 
-    public void addLog(String event, boolean extras) {
+    public void addLog(@NonNull String event, boolean extras) {
         addLog(event, extras, null);
     }
 
@@ -85,30 +85,30 @@
      * @param gestureEvent GestureEvent representing the event being logged.
      */
     public void addLog(
-            String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
+            @NonNull String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event), gestureEvent);
     }
 
     public void addLog(
-            String event,
+            @NonNull String event,
             int extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
     public void addLog(
-            String event,
+            @NonNull String event,
             boolean extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
-    public void addLog(CompoundString compoundString) {
+    public void addLog(@NonNull CompoundString compoundString) {
         addLog(compoundString, null);
     }
 
     public void addLog(
-            CompoundString compoundString,
+            @NonNull CompoundString compoundString,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
         if (lastEventLog == null || mCurrentLogId != lastEventLog.logId) {
@@ -216,6 +216,10 @@
             return gestureEvent;
         }
 
+        public int getDuplicateCount() {
+            return duplicateCount;
+        }
+
         private void update(
                 @NonNull CompoundString compoundString,
                 ActiveGestureErrorDetector.GestureEvent gestureEvent) {
@@ -259,21 +263,20 @@
 
         public CompoundString(String substring) {
             mIsNoOp = substring == null;
-            if (mIsNoOp) {
-                mSubstrings = null;
-                mArgs = null;
-                return;
+            mSubstrings = mIsNoOp ? null : new ArrayList<>();
+            mArgs = mIsNoOp ? null : new ArrayList<>();
+
+            if (!mIsNoOp) {
+                mSubstrings.add(substring);
             }
-            mSubstrings = new ArrayList<>();
-            mSubstrings.add(substring);
-            mArgs = new ArrayList<>();
         }
 
         public CompoundString append(CompoundString substring) {
-            if (mIsNoOp) {
+            if (mIsNoOp || substring.mIsNoOp) {
                 return this;
             }
             mSubstrings.addAll(substring.mSubstrings);
+            mArgs.addAll(substring.mArgs);
 
             return this;
         }
@@ -288,30 +291,53 @@
         }
 
         public CompoundString append(int num) {
+            if (mIsNoOp) {
+                return this;
+            }
+            mArgs.add(num);
+
+            return append("%d");
+        }
+
+        public CompoundString append(long num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%d");
         }
 
         public CompoundString append(float num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%.2f");
         }
 
         public CompoundString append(double num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%.2f");
         }
 
         public CompoundString append(boolean bool) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(bool);
 
             return append("%b");
         }
 
-        public Object[] getArgs() {
+        private Object[] getArgs() {
+            Preconditions.assertTrue(!mIsNoOp);
+
             return mArgs.toArray();
         }
 
@@ -320,7 +346,7 @@
             return String.format(toUnformattedString(), getArgs());
         }
 
-        public String toUnformattedString() {
+        private String toUnformattedString() {
             Preconditions.assertTrue(!mIsNoOp);
 
             StringBuilder sb = new StringBuilder();
@@ -333,7 +359,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(mIsNoOp, mSubstrings);
+            return Objects.hash(mIsNoOp, mSubstrings, mArgs);
         }
 
         @Override
@@ -342,7 +368,9 @@
                 return false;
             }
             CompoundString other = (CompoundString) obj;
-            return (mIsNoOp == other.mIsNoOp) && Objects.equals(mSubstrings, other.mSubstrings);
+            return (mIsNoOp == other.mIsNoOp)
+                    && Objects.equals(mSubstrings, other.mSubstrings)
+                    && Objects.equals(mArgs, other.mArgs);
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
index aeec36f..5efbb40 100644
--- a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
+++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
@@ -57,16 +57,16 @@
      * Registers the activity-created listener. If the activity is already created, then the
      * callback provided in the constructor will be called synchronously.
      */
-    public void register() {
+    public void register(String reasonString) {
         mIsRegistered = true;
-        mActivityTracker.registerCallback(this);
+        mActivityTracker.registerCallback(this, reasonString);
     }
 
     /**
      * After calling this, we won't {@link #init} even when the activity is ready.
      */
-    public void unregister() {
-        mActivityTracker.unregisterCallback(this);
+    public void unregister(String reasonString) {
+        mActivityTracker.unregisterCallback(this, reasonString);
         mIsRegistered = false;
         mOnInitListener = null;
     }
diff --git a/quickstep/src/com/android/quickstep/util/AnimUtils.java b/quickstep/src/com/android/quickstep/util/AnimUtils.java
index 7fbbb6e..8e3d44f 100644
--- a/quickstep/src/com/android/quickstep/util/AnimUtils.java
+++ b/quickstep/src/com/android/quickstep/util/AnimUtils.java
@@ -16,6 +16,15 @@
 
 package com.android.quickstep.util;
 
+import static com.android.app.animation.Interpolators.clampToProgress;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.os.Bundle;
+import android.os.IRemoteCallback;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.util.RunnableList;
+
 /**
  * Utility class containing methods to help manage animations, interpolators, and timings.
  */
@@ -48,4 +57,27 @@
                 ? SplitAnimationTimings.TABLET_APP_PAIR_LAUNCH
                 : SplitAnimationTimings.PHONE_APP_PAIR_LAUNCH;
     }
+
+    /**
+     * Returns a IRemoteCallback which completes the provided list as a result
+     */
+    public static IRemoteCallback completeRunnableListCallback(RunnableList list) {
+        return new IRemoteCallback.Stub() {
+            @Override
+            public void sendResult(Bundle bundle) {
+                MAIN_EXECUTOR.execute(list::executeAllAndDestroy);
+            }
+        };
+    }
+
+    /**
+     * Returns a function that runs the given interpolator such that the entire progress is set
+     * between the given duration. That is, we set the interpolation to 0 until startDelay and reach
+     * 1 by (startDelay + duration).
+     */
+    public static Interpolator clampToDuration(Interpolator interpolator, float startDelay,
+            float duration, float totalDuration) {
+        return clampToProgress(interpolator, startDelay / totalDuration,
+                (startDelay + duration) / totalDuration);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index cb35ec8..c9647f5 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -17,7 +17,7 @@
 
 import static com.android.app.animation.Interpolators.DECELERATE;
 import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
 
@@ -34,17 +34,17 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.AllAppsSwipeController;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.DeviceConfigWrapper;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * Controls an animation that can go beyond progress = 1, at which point resistance should be
@@ -58,6 +58,7 @@
         FROM_APP(0.75f, 0.5f, 1f, false),
         FROM_APP_TO_ALL_APPS(1f, 0.6f, 0.8f, false),
         FROM_APP_TABLET(1f, 0.7f, 1f, true),
+        FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true),
         FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false),
         FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
 
@@ -157,11 +158,12 @@
         PendingAnimation resistAnim = createRecentsResistanceAnim(params);
 
         // Apply All Apps animation during the resistance animation.
-        if (recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()) {
-            StatefulActivity activity =
-                    recentsOrientedState.getActivityInterface().getCreatedActivity();
-            if (activity != null) {
-                StateManager<LauncherState> stateManager = activity.getStateManager();
+        if (recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()) {
+            RecentsViewContainer container =
+                    recentsOrientedState.getContainerInterface().getCreatedContainer();
+            if (container != null) {
+                RecentsView recentsView = container.getOverviewPanel();
+                StateManager<LauncherState> stateManager = recentsView.getStateManager();
                 if (stateManager.isInStableState(LauncherState.BACKGROUND_APP)
                         && stateManager.isInTransition()) {
 
@@ -184,12 +186,12 @@
     private static float getAllAppsThreshold(Context context,
             RecentsOrientedState recentsOrientedState, DeviceProfile dp) {
         int transitionDragLength =
-                recentsOrientedState.getActivityInterface().getSwipeUpDestinationAndLength(
+                recentsOrientedState.getContainerInterface().getSwipeUpDestinationAndLength(
                         dp, context, TEMP_RECT,
                         recentsOrientedState.getOrientationHandler());
         float dragLengthFactor = (float) dp.heightPx / transitionDragLength;
         // -1s are because 0-1 is reserved for the normal transition.
-        float threshold = LauncherPrefs.get(context).get(ALL_APPS_OVERVIEW_THRESHOLD) / 100f;
+        float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
         return (threshold - 1) / (dragLengthFactor - 1);
     }
 
@@ -200,9 +202,9 @@
     public static <SCALE, TRANSLATION> PendingAnimation createRecentsResistanceAnim(
             RecentsParams<SCALE, TRANSLATION> params) {
         Rect startRect = new Rect();
-        PagedOrientationHandler orientationHandler = params.recentsOrientedState
+        RecentsPagedOrientationHandler orientationHandler = params.recentsOrientedState
                 .getOrientationHandler();
-        params.recentsOrientedState.getActivityInterface()
+        params.recentsOrientedState.getContainerInterface()
                 .calculateTaskSize(params.context, params.dp, startRect, orientationHandler);
         long distanceToCover = startRect.bottom;
         PendingAnimation resistAnim = params.resistAnim != null
@@ -239,10 +241,10 @@
         float stopResist =
                 params.resistanceParams.stopScalingAtTop ? 1f - startRect.top / endRectF.top : 1f;
         final TimeInterpolator scaleInterpolator = t -> {
-            if (t < startResist) {
+            if (t <= startResist) {
                 return t;
             }
-            if (t > stopResist) {
+            if (t >= stopResist) {
                 return maxResist;
             }
             float resistProgress = Utilities.getProgress(t, startResist, stopResist);
@@ -302,12 +304,14 @@
             this.translationProperty = translationProperty;
             if (dp.isTablet) {
                 resistanceParams =
-                        recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
+                        recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()
                                 ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET
-                                : RecentsResistanceParams.FROM_APP_TABLET;
+                                : enableGridOnlyOverview()
+                                        ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
+                                        : RecentsResistanceParams.FROM_APP_TABLET;
             } else {
                 resistanceParams =
-                        recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
+                        recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()
                                 ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS
                                 : RecentsResistanceParams.FROM_APP;
             }
diff --git a/quickstep/src/com/android/quickstep/util/AppCloseConfig.java b/quickstep/src/com/android/quickstep/util/AppCloseConfig.java
deleted file mode 100644
index bec3379..0000000
--- a/quickstep/src/com/android/quickstep/util/AppCloseConfig.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import android.annotation.FloatRange;
-import android.annotation.IntRange;
-
-/*
- * Adds getter methods to {@link MultiValueUpdateListener} specific to app close animation,
- * so that the entire animation can be defined in one place.
- */
-public abstract class AppCloseConfig extends MultiValueUpdateListener {
-
-    /**
-     * Returns the translation y of the workspace contents.
-     */
-    public abstract float getWorkspaceTransY();
-
-    /*
-     * Returns the scale of the workspace contents.
-     */
-    public abstract float getWorkspaceScale();
-
-    /*
-     * Returns the alpha of the window.
-     */
-    public abstract @FloatRange(from = 0, to = 1) float getWindowAlpha();
-
-    /*
-     * Returns the alpha of the foreground layer of an adaptive icon.
-     */
-    public abstract @IntRange(from = 0, to = 255) int getFgAlpha();
-
-    /*
-     * Returns the corner radius of the window and icon.
-     */
-    public abstract float getCornerRadius();
-
-    /*
-     * Returns the interpolated progress of the animation.
-     */
-    public abstract float getInterpolatedProgress();
-
-}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 3ca2531..a82031a 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -17,37 +17,58 @@
 
 package com.android.quickstep.util;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
+import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_LAUNCH;
+import static com.android.launcher3.model.data.AppInfo.PACKAGE_KEY_COMPARATOR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.isPersistentSnapPosition;
 
-import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import android.util.Pair;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.launcher3.Launcher;
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
 
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Controller class that handles app pair interactions: saving, modifying, deleting, etc.
@@ -58,6 +79,8 @@
  * ratio.
  */
 public class AppPairsController {
+    private static final String TAG = "AppPairsController";
+
     // Used for encoding and decoding the "rank" attribute
     private static final int BITMASK_SIZE = 16;
     private static final int BITMASK_FOR_SNAP_POSITION = (1 << BITMASK_SIZE) - 1;
@@ -78,38 +101,74 @@
     }
 
     /**
-     * Creates a new app pair ItemInfo and adds it to the workspace
+     * Creates a new app pair ItemInfo and adds it to the workspace.
+     * <br>
+     * We create WorkspaceItemInfos to save onto the app pair in the following way:
+     * <br> 1. We verify that the ComponentKey from our Recents tile corresponds to a real
+     * launchable app in the app store.
+     * <br> 2. If it doesn't, we search for the underlying launchable app via package name, and use
+     * that instead.
+     * <br> 3. If that fails, we re-use the existing WorkspaceItemInfo by cloning it and replacing
+     * its intent with one from PackageManager.
+     * <br> 4. If everything fails, we just use the WorkspaceItemInfo as is, with its existing
+     * intent. This is not preferred, but will still work in most cases (notably it will not work
+     * well on trampoline apps).
      */
     public void saveAppPair(GroupedTaskView gtv) {
+        InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
         TaskView.TaskIdAttributeContainer[] attributes = gtv.getTaskIdAttributeContainers();
-        WorkspaceItemInfo app1 = attributes[0].getItemInfo().clone();
-        WorkspaceItemInfo app2 = attributes[1].getItemInfo().clone();
-        app1.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-        app2.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+        WorkspaceItemInfo recentsInfo1 = attributes[0].getItemInfo();
+        WorkspaceItemInfo recentsInfo2 = attributes[1].getItemInfo();
+        WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
+        WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
+
+        // If app lookup fails, use the WorkspaceItemInfo that we have, but try to override default
+        // intent with one from PackageManager.
+        if (app1 == null) {
+            Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo1.title
+                    + " failed. Falling back to the WorkspaceItemInfo from Recents.");
+            app1 = convertRecentsItemToAppItem(recentsInfo1);
+        }
+        if (app2 == null) {
+            Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo2.title
+                    + " failed. Falling back to the WorkspaceItemInfo from Recents.");
+            app2 = convertRecentsItemToAppItem(recentsInfo2);
+        }
+
+        // WorkspaceItemProcessor won't process these new ItemInfos until the next launcher restart,
+        // so update some flags now.
+        updateWorkspaceItemFlags(app1);
+        updateWorkspaceItemFlags(app2);
 
         @PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
         if (!isPersistentSnapPosition(snapPosition)) {
-            throw new RuntimeException("tried to save an app pair with illegal snapPosition");
+            // if we received an illegal snap position, log an error and do not create the app pair.
+            Log.wtf(TAG, "tried to save an app pair with illegal snapPosition " + snapPosition);
+            return;
         }
 
         app1.rank = encodeRank(SPLIT_POSITION_TOP_OR_LEFT, snapPosition);
         app2.rank = encodeRank(SPLIT_POSITION_BOTTOM_OR_RIGHT, snapPosition);
-        FolderInfo newAppPair = FolderInfo.createAppPair(app1, app2);
+        AppPairInfo newAppPair = new AppPairInfo(app1, app2);
 
         IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
         MODEL_EXECUTOR.execute(() -> {
-            newAppPair.contents.forEach(member -> {
+            newAppPair.getAppContents().forEach(member -> {
                 member.title = "";
                 member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
                 iconCache.getTitleAndIcon(member, member.usingLowResIcon());
             });
-            newAppPair.title = getDefaultTitle(newAppPair.contents.get(0).title,
-                    newAppPair.contents.get(1).title);
             MAIN_EXECUTOR.execute(() -> {
                 LauncherAccessibilityDelegate delegate =
-                        Launcher.getLauncher(mContext).getAccessibilityDelegate();
+                        QuickstepLauncher.getLauncher(mContext).getAccessibilityDelegate();
                 if (delegate != null) {
-                    delegate.addToWorkspace(newAppPair, true);
+                    delegate.addToWorkspace(newAppPair, true, (success) -> {
+                        if (success) {
+                            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
+                        } else {
+                            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
+                        }
+                    });
                     mStatsLogManager.logger().withItemInfo(newAppPair)
                             .log(StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_SAVE);
                 }
@@ -120,24 +179,30 @@
     /**
      * Launches an app pair by searching the RecentsModel for running instances of each app, and
      * staging either those running instances or launching the apps as new Intents.
+     *
+     * @param cuj Should be an integer from {@link Cuj} or -1 if no CUJ needs to be logged for jank
+     *            monitoring
      */
-    public void launchAppPair(AppPairIcon appPairIcon) {
-        WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
-        WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
+    public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
+        WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
+        WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
         ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
         ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
+        mSplitSelectStateController.setLaunchingCuj(cuj);
+        InteractionJankMonitorWrapper.begin(appPairIcon, cuj);
+
         mSplitSelectStateController.findLastActiveTasksAndRunCallback(
                 Arrays.asList(app1Key, app2Key),
                 false /* findExactPairMatch */,
                 foundTasks -> {
-                    @Nullable Task foundTask1 = foundTasks.get(0);
+                    @Nullable Task foundTask1 = foundTasks[0];
                     Intent task1Intent;
                     int task1Id;
                     if (foundTask1 != null) {
                         task1Id = foundTask1.key.id;
                         task1Intent = null;
                     } else {
-                        task1Id = ActivityTaskManager.INVALID_TASK_ID;
+                        task1Id = INVALID_TASK_ID;
                         task1Intent = app1.intent;
                     }
 
@@ -147,12 +212,12 @@
                             LAUNCHER_APP_PAIR_LAUNCH,
                             task1Id);
 
-                    @Nullable Task foundTask2 = foundTasks.get(1);
+                    @Nullable Task foundTask2 = foundTasks[1];
                     if (foundTask2 != null) {
-                        mSplitSelectStateController.setSecondTask(foundTask2);
+                        mSplitSelectStateController.setSecondTask(foundTask2, app2);
                     } else {
                         mSplitSelectStateController.setSecondTask(
-                                app2.intent, app2.user);
+                                app2.intent, app2.user, app2);
                     }
 
                     mSplitSelectStateController.setLaunchingIconView(appPairIcon);
@@ -164,6 +229,236 @@
     }
 
     /**
+     * Creates a new launchable WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION by looking the
+     * ComponentKey up in the AllAppsStore. If no app is found, attempts a lookup by package
+     * instead. If that lookup fails, returns null.
+     */
+    @Nullable
+    private WorkspaceItemInfo lookupLaunchableItem(@Nullable ComponentKey key) {
+        if (key == null) {
+            return null;
+        }
+
+        AllAppsStore appsStore = ActivityContext.lookupContext(mContext)
+                .getAppsView().getAppsStore();
+
+        // Lookup by ComponentKey
+        AppInfo appInfo = appsStore.getApp(key);
+        if (appInfo == null) {
+            // Lookup by package
+            appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR);
+        }
+
+        return appInfo != null ? appInfo.makeWorkspaceItem(mContext) : null;
+    }
+
+    /**
+     * Updates flags for newly created WorkspaceItemInfos.
+     */
+    private void updateWorkspaceItemFlags(WorkspaceItemInfo wii) {
+        PackageManager pm = mContext.getPackageManager();
+        ActivityInfo ai = null;
+        try {
+            ai = pm.getActivityInfo(wii.getTargetComponent(), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "PackageManager lookup failed.");
+        }
+
+        if (ai != null) {
+            wii.setNonResizeable(ai.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE);
+        }
+    }
+
+    /**
+     * Converts a WorkspaceItemInfo of itemType=ITEM_TYPE_TASK (from a Recents task) to a new
+     * WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION.
+     */
+    private WorkspaceItemInfo convertRecentsItemToAppItem(WorkspaceItemInfo recentsItem) {
+        if (recentsItem.itemType != LauncherSettings.Favorites.ITEM_TYPE_TASK) {
+            Log.w(TAG, "Expected ItemInfo of type ITEM_TYPE_TASK, but received "
+                    + recentsItem.itemType);
+        }
+
+        WorkspaceItemInfo launchableItem = recentsItem.clone();
+        PackageManager p = mContext.getPackageManager();
+        Intent launchIntent = p.getLaunchIntentForPackage(recentsItem.getTargetPackage());
+        Log.w(TAG, "Initial intent from Recents: " + launchableItem.intent + "\n"
+                + "Intent from PackageManager: " + launchIntent);
+        if (launchIntent != null) {
+            // If lookup from PackageManager fails, just use the existing intent
+            launchableItem.intent = launchIntent;
+        }
+        launchableItem.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+        return launchableItem;
+    }
+
+    /**
+     * Handles the complicated logic for how to animate an app pair entrance when already inside an
+     * app or app pair.
+     *
+     * If the user tapped on an app pair while already in an app pair, there are 4 general cases:
+     *   a) Clicked app pair A|B, but both apps are already running on screen.
+     *   b) App A is already on-screen, but App B isn't.
+     *   c) App B is on-screen, but App A isn't.
+     *   d) Neither is on-screen.
+     *
+     * If the user tapped an app pair while inside a single app, there are 3 cases:
+     *   a) The on-screen app is App A of the app pair.
+     *   b) The on-screen app is App B of the app pair.
+     *   c) It is neither.
+     *
+     * For each case, we call the appropriate animation and split launch type.
+     */
+    public void handleAppPairLaunchInApp(AppPairIcon launchingIconView,
+            List<? extends ItemInfo> itemInfos) {
+        TaskbarActivityContext context = (TaskbarActivityContext) launchingIconView.getContext();
+        List<ComponentKey> componentKeys =
+                itemInfos.stream().map(ItemInfo::getComponentKey).toList();
+
+        // Use TopTaskTracker to find the currently running app (or apps)
+        TopTaskTracker topTaskTracker = getTopTaskTracker();
+
+        // getRunningSplitTasksIds() will return a pair of ids if we are currently running a
+        // split pair, or an empty array with zero length if we are running a single app.
+        int[] runningSplitTasks = topTaskTracker.getRunningSplitTaskIds();
+        if (runningSplitTasks != null && runningSplitTasks.length == 2) {
+            // Tapped an app pair while in an app pair
+            int runningTaskId1 = runningSplitTasks[0];
+            int runningTaskId2 = runningSplitTasks[1];
+
+            mSplitSelectStateController.findLastActiveTasksAndRunCallback(
+                    componentKeys,
+                    false /* findExactPairMatch */,
+                    foundTasks -> {
+                        // If our clicked app pair has already-running Tasks, we grab the
+                        // taskIds here so we can see if those ids are already on-screen now
+                        List<Integer> lastActiveTasksOfAppPair =
+                                Arrays.stream(foundTasks).map((Task task) -> {
+                                    if (task != null) {
+                                        return task.getKey().getId();
+                                    } else {
+                                        return INVALID_TASK_ID;
+                                    }
+                                }).toList();
+
+                        if (lastActiveTasksOfAppPair.contains(runningTaskId1)
+                                && lastActiveTasksOfAppPair.contains(runningTaskId2)) {
+                            // App A and App B are already on-screen, so do nothing.
+                        } else if (!lastActiveTasksOfAppPair.contains(runningTaskId1)
+                                && !lastActiveTasksOfAppPair.contains(runningTaskId2)) {
+                            // Neither A nor B are on screen, so just launch a new app pair
+                            // normally.
+                            launchAppPair(launchingIconView,
+                                    CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR);
+                        } else {
+                            // Exactly one app (A or B) is on-screen, so we have to launch the other
+                            // on the appropriate side.
+                            ItemInfo app1 = itemInfos.get(0);
+                            ItemInfo app2 = itemInfos.get(1);
+                            int task1 = lastActiveTasksOfAppPair.get(0);
+                            int task2 = lastActiveTasksOfAppPair.get(1);
+
+                            // If task1 is one of the running on-screen tasks, we launch app2.
+                            // If not, task2 must be the running task, and we launch app1.
+                            ItemInfo appToLaunch =
+                                    task1 == runningTaskId1 || task1 == runningTaskId2
+                                            ? app2
+                                            : app1;
+                            // If the on-screen task is on the bottom/right position, we launch to
+                            // the top/left. If not, we launch to the bottom/right.
+                            @StagePosition int sideToLaunch =
+                                    task1 == runningTaskId2 || task2 == runningTaskId2
+                                            ? STAGE_POSITION_TOP_OR_LEFT
+                                            : STAGE_POSITION_BOTTOM_OR_RIGHT;
+
+                            launchToSide(context, launchingIconView.getInfo(), appToLaunch,
+                                    sideToLaunch);
+                        }
+                    }
+            );
+        } else {
+            // Tapped an app pair while in a single app
+            int runningTaskId = topTaskTracker
+                    .getCachedTopTask(false /* filterOnlyVisibleRecents */).getTaskId();
+
+            mSplitSelectStateController.findLastActiveTasksAndRunCallback(
+                    componentKeys,
+                    false /* findExactPairMatch */,
+                    foundTasks -> {
+                        Task foundTask1 = foundTasks[0];
+                        Task foundTask2 = foundTasks[1];
+                        boolean task1IsOnScreen =
+                                foundTask1 != null && foundTask1.getKey().getId() == runningTaskId;
+                        boolean task2IsOnScreen =
+                                foundTask2 != null && foundTask2.getKey().getId() == runningTaskId;
+
+                        if (!task1IsOnScreen && !task2IsOnScreen) {
+                            // Neither App A nor App B are on-screen, launch the app pair normally.
+                            launchAppPair(launchingIconView,
+                                    CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR);
+                        } else {
+                            // Either A or B is on-screen, so launch the other on the appropriate
+                            // side.
+                            ItemInfo app1 = itemInfos.get(0);
+                            ItemInfo app2 = itemInfos.get(1);
+                            // If task1 is the running on-screen task, we launch app2 on the
+                            // bottom/right. If task2 is on-screen, launch app1 on the top/left.
+                            ItemInfo appToLaunch = task1IsOnScreen ? app2 : app1;
+                            @StagePosition int sideToLaunch = task1IsOnScreen
+                                    ? STAGE_POSITION_BOTTOM_OR_RIGHT
+                                    : STAGE_POSITION_TOP_OR_LEFT;
+
+                            launchToSide(context, launchingIconView.getInfo(), appToLaunch,
+                                    sideToLaunch);
+                        }
+                }
+            );
+        }
+    }
+
+    /**
+     * Executes a split launch by launching an app to the side of an existing app.
+     * @param context The TaskbarActivityContext that we are launching the app pair from.
+     * @param launchingItemInfo The itemInfo of the icon that was tapped.
+     * @param app The app that will launch to the side of the existing running app (not necessarily
+     *  the same as the previous parameter; e.g. we tap an app pair but launch an app).
+     * @param side A @StagePosition, either STAGE_POSITION_TOP_OR_LEFT or
+     *  STAGE_POSITION_BOTTOM_OR_RIGHT.
+     */
+    @VisibleForTesting
+    public void launchToSide(
+            TaskbarActivityContext context,
+            ItemInfo launchingItemInfo,
+            ItemInfo app,
+            @StagePosition int side
+    ) {
+        LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+
+        // Set up to log app pair launch event
+        Pair<com.android.internal.logging.InstanceId, InstanceId> instanceIds =
+                LogUtils.getShellShareableInstanceId();
+        context.getStatsLogManager()
+                .logger()
+                .withItemInfo(launchingItemInfo)
+                .withInstanceId(instanceIds.second)
+                .log(LAUNCHER_APP_PAIR_LAUNCH);
+
+        SystemUiProxy.INSTANCE.get(context)
+                .startIntent(
+                        launcherApps.getMainActivityLaunchIntent(
+                                app.getIntent().getComponent(),
+                                null,
+                                app.user
+                        ),
+                        app.user.getIdentifier(),
+                        new Intent(),
+                        side,
+                        null,
+                        instanceIds.first
+                );
+    }
+
+    /**
      * App pair members have a "rank" attribute that contains information about the split position
      * and ratio. We implement this by splitting the int in half (e.g. 16 bits each), then use one
      * half to store splitPosition (left vs right) and the other half to store snapPosition
@@ -191,9 +486,10 @@
     }
 
     /**
-     * Returns a formatted default title for the app pair.
+     * Gets the TopTaskTracker, which is a cached record of the top running Task.
      */
-    public String getDefaultTitle(CharSequence app1, CharSequence app2) {
-        return mContext.getString(R.string.app_pair_default_title, app1, app2);
+    @VisibleForTesting
+    public TopTaskTracker getTopTaskTracker() {
+        return TopTaskTracker.INSTANCE.get(mContext);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index f7437eb..4a35c3b 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -20,11 +20,13 @@
 import com.android.launcher3.R;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.io.PrintWriter;
+import java.util.Optional;
 
 /** Class to manage Assistant states. */
-public class AssistStateManager implements ResourceBasedOverride {
+public class AssistStateManager implements ResourceBasedOverride, SafeCloseable {
 
     public static final MainThreadInitializedObject<AssistStateManager> INSTANCE =
             forOverride(AssistStateManager.class, R.string.assist_state_manager_class);
@@ -41,31 +43,61 @@
         return false;
     }
 
-    /** Whether search recovery is available. */
-    public boolean isVisRecoveryEnabled() {
+    /** Whether search supports showing on the lockscreen. */
+    public boolean supportsShowWhenLocked() {
         return false;
     }
 
-    /** Whether search recovery is available. */
-    public boolean isOseRecoveryEnabled() {
-        return false;
+    /** Whether CsHelper CtS invocation path is available. */
+    public Optional<Boolean> isCsHelperAvailable() {
+        return Optional.empty();
     }
 
-    /** Whether search recovery is available. */
-    public boolean isOseShowSessionEnabled() {
-        return false;
+    /** Whether VIS CtS invocation path is available. */
+    public Optional<Boolean> isVisAvailable() {
+        return Optional.empty();
+    }
+
+    /** Get the Launcher overridden long press nav handle duration to trigger Assistant. */
+    public Optional<Long> getLPNHDurationMillis() {
+        return Optional.empty();
+    }
+
+    /**
+     * Get the Launcher overridden long press nav handle touch slop multiplier to trigger Assistant.
+     */
+    public Optional<Float> getLPNHCustomSlopMultiplier() {
+        return Optional.empty();
+    }
+
+    /** Get the Launcher overridden long press home duration to trigger Assistant. */
+    public Optional<Long> getLPHDurationMillis() {
+        return Optional.empty();
+    }
+
+    /** Get the Launcher overridden long press home touch slop multiplier to trigger Assistant. */
+    public Optional<Float> getLPHCustomSlopMultiplier() {
+        return Optional.empty();
+    }
+
+    /** Get the long press duration data source. */
+    public int getDurationDataSource() {
+        return 0;
+    }
+
+    /** Get the long press touch slop multiplier data source. */
+    public int getSlopDataSource() {
+        return 0;
     }
 
     /** Return {@code true} if the Settings toggle is enabled. */
-    public boolean isSettingsNavHandleEnabled() {
-        return false;
-    }
-
-    /** Return {@code true} if the Settings toggle is enabled. */
-    public boolean isSettingsHomeButtonEnabled() {
+    public boolean isSettingsAllEntrypointsEnabled() {
         return false;
     }
 
     /** Dump states. */
     public void dump(String prefix, PrintWriter writer) {}
+
+    @Override
+    public void close() {}
 }
diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
index 99f564c..5d6bb1d 100644
--- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java
+++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
+
 import android.app.WallpaperManager;
 import android.os.IBinder;
 import android.util.FloatProperty;
@@ -33,6 +35,9 @@
  * Utility class for applying depth effect
  */
 public class BaseDepthController {
+    public static final float DEPTH_0_PERCENT = 0f;
+    public static final float DEPTH_60_PERCENT = 0.6f;
+    public static final float DEPTH_70_PERCENT = 0.7f;
 
     private static final FloatProperty<BaseDepthController> DEPTH =
             new FloatProperty<BaseDepthController>("depth") {
@@ -127,10 +132,14 @@
         float depth = mDepth;
         IBinder windowToken = mLauncher.getRootView().getWindowToken();
         if (windowToken != null) {
-            // The API's full zoom-out is three times larger than the zoom-out we apply to the
-            // icons. To keep the two consistent throughout the animation while keeping Launcher's
-            // concept of full depth unchanged, we divide the depth by 3 here.
-            mWallpaperManager.setWallpaperZoomOut(windowToken, depth / 3);
+            if (enableScalingRevealHomeAnimation()) {
+                mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
+            } else {
+                // The API's full zoom-out is three times larger than the zoom-out we apply to the
+                // icons. To keep the two consistent throughout the animation while keeping
+                // Launcher's concept of full depth unchanged, we divide the depth by 3 here.
+                mWallpaperManager.setWallpaperZoomOut(windowToken, depth / 3);
+            }
         }
 
         if (!BlurUtils.supportsBlursOnWindows()) {
@@ -150,8 +159,15 @@
         boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque();
         boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg && !mPauseBlurs;
 
+        float blurAmount;
+        if (enableScalingRevealHomeAnimation()) {
+            blurAmount = mapDepthToBlur(depth);
+        } else {
+            blurAmount = depth;
+        }
         mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg || mPauseBlurs
-                ? 0 : (int) (depth * mMaxBlurRadius);
+                ? 0 : (int) (blurAmount * mMaxBlurRadius);
+
         SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
                 .setBackgroundBlurRadius(mSurface, mCurrentBlur)
                 .setOpaque(mSurface, isSurfaceOpaque);
@@ -197,4 +213,12 @@
             applyDepthAndBlur();
         }
     }
+
+    /**
+     * Maps depth values to blur amounts as a percentage of the max blur.
+     * The blur percentage grows linearly with depth, and maxes out at 30% depth.
+     */
+    private static float mapDepthToBlur(float depth) {
+        return Math.min(3 * depth, 1f);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/CancellableTask.java b/quickstep/src/com/android/quickstep/util/CancellableTask.java
deleted file mode 100644
index a6e2e81..0000000
--- a/quickstep/src/com/android/quickstep/util/CancellableTask.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-
-/**
- * Utility class to executore a task on background and post the result on UI thread
- */
-public abstract class CancellableTask<T> implements Runnable {
-
-    private boolean mCancelled = false;
-
-    @Override
-    public final void run() {
-        if (mCancelled) {
-            return;
-        }
-        T result = getResultOnBg();
-        if (mCancelled) {
-            return;
-        }
-        MAIN_EXECUTOR.execute(() -> {
-            if (mCancelled) {
-                return;
-            }
-            handleResult(result);
-        });
-    }
-
-    /**
-     * Called on the worker thread to process the request. The return object is passed to
-     * {@link #handleResult(Object)}
-     */
-    @WorkerThread
-    public abstract T getResultOnBg();
-
-    /**
-     * Called on the UI thread to handle the final result.
-     * @param result
-     */
-    @UiThread
-    public abstract void handleResult(T result);
-
-    /**
-     * Cancels the request. If it is called before {@link #handleResult(Object)}, that method
-     * will not be called
-     */
-    public void cancel() {
-        mCancelled = true;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
new file mode 100644
index 0000000..544c64d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.app.ActivityThread
+import android.content.Context
+import android.content.SharedPreferences
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import android.provider.DeviceConfig
+import android.provider.DeviceConfig.OnPropertiesChangedListener
+import android.provider.DeviceConfig.Properties
+import androidx.annotation.WorkerThread
+import com.android.launcher3.BuildConfig
+import com.android.launcher3.util.Executors
+
+/** Utility class to manage a set of device configurations */
+class DeviceConfigHelper<ConfigType>(private val factory: (PropReader) -> ConfigType) {
+
+    var config: ConfigType
+        private set
+    private val allKeys: Set<String>
+    private val propertiesListener = OnPropertiesChangedListener { onDevicePropsChanges(it) }
+    private val sharedPrefChangeListener = OnSharedPreferenceChangeListener { _, _ ->
+        recreateConfig()
+    }
+
+    private val changeListeners = mutableListOf<Runnable>()
+
+    init {
+        // Initialize the default config once.
+        allKeys = HashSet()
+        config =
+            factory(
+                PropReader(
+                    object : PropProvider {
+                        override fun <T : Any> get(key: String, fallback: T): T {
+                            if (fallback is Int)
+                                return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
+                            else if (fallback is Boolean)
+                                return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
+                                    as T
+                            else return fallback
+                        }
+                    }
+                )
+            )
+
+        DeviceConfig.addOnPropertiesChangedListener(
+            NAMESPACE_LAUNCHER,
+            Executors.UI_HELPER_EXECUTOR,
+            propertiesListener
+        )
+        if (BuildConfig.IS_DEBUG_DEVICE) {
+            prefs.registerOnSharedPreferenceChangeListener(sharedPrefChangeListener)
+        }
+    }
+
+    @WorkerThread
+    private fun onDevicePropsChanges(properties: Properties) {
+        if (NAMESPACE_LAUNCHER != properties.namespace) return
+        if (!allKeys.any(properties.keyset::contains)) return
+        recreateConfig()
+    }
+
+    private fun recreateConfig() {
+        val myProps =
+            DeviceConfig.getProperties(NAMESPACE_LAUNCHER, *allKeys.toTypedArray<String>())
+        config =
+            factory(
+                PropReader(
+                    object : PropProvider {
+                        override fun <T : Any> get(key: String, fallback: T): T {
+                            if (fallback is Int) return myProps.getInt(key, fallback) as T
+                            else if (fallback is Boolean)
+                                return myProps.getBoolean(key, fallback) as T
+                            else return fallback
+                        }
+                    }
+                )
+            )
+        Executors.MAIN_EXECUTOR.execute { changeListeners.forEach(Runnable::run) }
+    }
+
+    /** Adds a listener for property changes */
+    fun addChangeListener(r: Runnable) = changeListeners.add(r)
+
+    /** Removes a previously added listener */
+    fun removeChangeListener(r: Runnable) = changeListeners.remove(r)
+
+    fun close() {
+        DeviceConfig.removeOnPropertiesChangedListener(propertiesListener)
+        if (BuildConfig.IS_DEBUG_DEVICE) {
+            prefs.unregisterOnSharedPreferenceChangeListener(sharedPrefChangeListener)
+        }
+    }
+
+    internal interface PropProvider {
+        fun <T : Any> get(key: String, fallback: T): T
+    }
+
+    /** The reader is sent to the config for initialization */
+    class PropReader internal constructor(private val f: PropProvider) {
+
+        @JvmOverloads
+        fun <T : Any> get(key: String, fallback: T, desc: String? = null): T {
+            val v = f.get(key, fallback)
+            if (BuildConfig.IS_DEBUG_DEVICE && desc != null) {
+                if (v is Int) {
+                    allProps[key] = DebugInfo(key, desc, true, fallback)
+                    return prefs.getInt(key, v) as T
+                } else if (v is Boolean) {
+                    allProps[key] = DebugInfo(key, desc, false, fallback)
+                    return prefs.getBoolean(key, v) as T
+                }
+            }
+            return v
+        }
+    }
+
+    class DebugInfo<T>(
+        val key: String,
+        val desc: String,
+        val isInt: Boolean,
+        val valueInCode: T,
+    )
+
+    companion object {
+        const val NAMESPACE_LAUNCHER = "launcher"
+
+        val allProps = mutableMapOf<String, DebugInfo<*>>()
+
+        private const val FLAGS_PREF_NAME = "featureFlags"
+
+        val prefs: SharedPreferences by lazy {
+            ActivityThread.currentApplication()
+                .createDeviceProtectedStorageContext()
+                .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
index 5cce728..e6e94e6 100644
--- a/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
+++ b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
@@ -20,30 +20,15 @@
 import android.os.RemoteException
 import android.view.SurfaceControl
 import android.view.SurfaceControl.Transaction
-import android.window.IRemoteTransition
 import android.window.IRemoteTransitionFinishedCallback
+import android.window.RemoteTransitionStub
 import android.window.TransitionInfo
 import com.android.launcher3.anim.AnimatorListeners.forEndCallback
 import com.android.launcher3.util.Executors
-import com.android.wm.shell.util.TransitionUtil
+import com.android.wm.shell.shared.TransitionUtil
 
 /** Remote animation which fades out the closing targets */
-class FadeOutRemoteTransition : IRemoteTransition.Stub() {
-
-    override fun mergeAnimation(
-        iBinder: IBinder,
-        transitionInfo: TransitionInfo,
-        transaction: Transaction,
-        mergeTarget: IBinder,
-        finishCB: IRemoteTransitionFinishedCallback
-    ) {
-
-        try {
-            finishCB.onTransitionFinished(null, Transaction())
-        } catch (e: RemoteException) {
-            // Ignore
-        }
-    }
+class FadeOutRemoteTransition : RemoteTransitionStub() {
 
     override fun startAnimation(
         transition: IBinder,
@@ -83,7 +68,4 @@
 
         Executors.MAIN_EXECUTOR.execute { anim.start() }
     }
-
-    override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) {
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/GestureExclusionManager.kt b/quickstep/src/com/android/quickstep/util/GestureExclusionManager.kt
new file mode 100644
index 0000000..24b0e3a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/GestureExclusionManager.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.graphics.Region
+import android.os.RemoteException
+import android.util.Log
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.ISystemGestureExclusionListener
+import android.view.IWindowManager
+import android.view.WindowManagerGlobal
+import androidx.annotation.BinderThread
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.util.Executors
+
+/** Wrapper over system gesture exclusion listener to optimize for multiple RPCs */
+class GestureExclusionManager(private val windowManager: IWindowManager) {
+
+    private val listeners = mutableListOf<ExclusionListener>()
+
+    private var lastExclusionRegion: Region? = null
+    private var lastUnrestrictedOrNull: Region? = null
+
+    @VisibleForTesting
+    val exclusionListener =
+        object : ISystemGestureExclusionListener.Stub() {
+            @BinderThread
+            override fun onSystemGestureExclusionChanged(
+                displayId: Int,
+                exclusionRegion: Region?,
+                unrestrictedOrNull: Region?
+            ) {
+                if (displayId != DEFAULT_DISPLAY) {
+                    return
+                }
+                Executors.MAIN_EXECUTOR.execute {
+                    lastExclusionRegion = exclusionRegion
+                    lastUnrestrictedOrNull = unrestrictedOrNull
+                    listeners.forEach {
+                        it.onGestureExclusionChanged(exclusionRegion, unrestrictedOrNull)
+                    }
+                }
+            }
+        }
+
+    /** Adds a listener for receiving gesture exclusion regions */
+    fun addListener(listener: ExclusionListener) {
+        val wasEmpty = listeners.isEmpty()
+        listeners.add(listener)
+        if (wasEmpty) {
+            Executors.UI_HELPER_EXECUTOR.execute {
+                try {
+                    windowManager.registerSystemGestureExclusionListener(
+                        exclusionListener,
+                        DEFAULT_DISPLAY
+                    )
+                } catch (e: RemoteException) {
+                    Log.e(TAG, "Failed to register gesture exclusion listener", e)
+                }
+            }
+        } else {
+            // If we had already registered before, dispatch the last known value,
+            // otherwise registering the listener will initiate a dispatch
+            listener.onGestureExclusionChanged(lastExclusionRegion, lastUnrestrictedOrNull)
+        }
+    }
+
+    /** Removes a previously added exclusion listener */
+    fun removeListener(listener: ExclusionListener) {
+        if (listeners.remove(listener) && listeners.isEmpty()) {
+            Executors.UI_HELPER_EXECUTOR.execute {
+                try {
+                    windowManager.unregisterSystemGestureExclusionListener(
+                        exclusionListener,
+                        DEFAULT_DISPLAY
+                    )
+                } catch (e: RemoteException) {
+                    Log.e(TAG, "Failed to unregister gesture exclusion listener", e)
+                }
+            }
+        }
+    }
+
+    interface ExclusionListener {
+        fun onGestureExclusionChanged(exclusionRegion: Region?, unrestrictedOrNull: Region?)
+    }
+
+    companion object {
+
+        private const val TAG = "GestureExclusionManager"
+
+        @JvmField
+        val INSTANCE = GestureExclusionManager(WindowManagerGlobal.getWindowManagerService()!!)
+
+        @JvmField val EMPTY_REGION = Region()
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
index 8209c09..843619d 100644
--- a/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
+++ b/quickstep/src/com/android/quickstep/util/InputProxyHandlerFactory.java
@@ -17,11 +17,11 @@
 
 import androidx.annotation.UiThread;
 
-import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.inputconsumers.OverviewInputConsumer;
+import com.android.quickstep.views.RecentsViewContainer;
 
 import java.util.function.Supplier;
 
@@ -31,13 +31,13 @@
  */
 public class InputProxyHandlerFactory implements Supplier<InputConsumer> {
 
-    private final BaseActivityInterface mActivityInterface;
+    private final BaseContainerInterface mContainerInterface;
     private final GestureState mGestureState;
 
     @UiThread
-    public InputProxyHandlerFactory(BaseActivityInterface activityInterface,
+    public InputProxyHandlerFactory(BaseContainerInterface activityInterface,
             GestureState gestureState) {
-        mActivityInterface = activityInterface;
+        mContainerInterface = activityInterface;
         mGestureState = gestureState;
     }
 
@@ -46,8 +46,8 @@
      */
     @Override
     public InputConsumer get() {
-        StatefulActivity activity = mActivityInterface.getCreatedActivity();
-        return activity == null ? InputConsumer.NO_OP
-                : new OverviewInputConsumer(mGestureState, activity, null, true);
+        RecentsViewContainer container = mContainerInterface.getCreatedContainer();
+        return container == null ? InputConsumer.NO_OP
+                : new OverviewInputConsumer(mGestureState, container, null, true);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 61ba5ac..4474f33 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -30,9 +30,9 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.HorizontalInsettableView;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.unfold.LauncherJankMonitorTransitionProgressListener;
@@ -56,7 +56,7 @@
     private static final FloatProperty<Hotseat> HOTSEAT_SCALE_PROPERTY =
             HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_UNFOLD_ANIMATION);
 
-    private final Launcher mLauncher;
+    private final QuickstepLauncher mLauncher;
     private final ScopedUnfoldTransitionProgressProvider mProgressProvider;
     private final NaturalRotationUnfoldProgressProvider mNaturalOrientationProgressProvider;
     private final UnfoldMoveFromCenterHotseatAnimator mUnfoldMoveFromCenterHotseatAnimator;
@@ -73,7 +73,7 @@
     private HorizontalInsettableView mQsbInsettable;
 
     public LauncherUnfoldAnimationController(
-            Launcher launcher,
+            QuickstepLauncher launcher,
             WindowManager windowManager,
             UnfoldTransitionProgressProvider unfoldTransitionProgressProvider,
             RotationChangeProvider rotationChangeProvider) {
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 79656c2..ec1eeb1 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -21,10 +21,10 @@
 import android.view.ViewGroup;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 
 public class LayoutUtils {
 
@@ -40,7 +40,7 @@
     }
 
     public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
-            PagedOrientationHandler orientationHandler) {
+            RecentsPagedOrientationHandler orientationHandler) {
         // Track the bottom of the window.
         Rect taskSize = new Rect();
         LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index a8a96ce..b8bc828 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -96,8 +96,14 @@
         mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
         mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
         mForcePauseTimeout = new Alarm();
-        mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */,
-                "Force pause timeout after " +  alarm.getLastSetTimeout() + "ms" /* reason */));
+        mForcePauseTimeout.setOnAlarmListener(alarm -> {
+            ActiveGestureLog.CompoundString log =
+                    new ActiveGestureLog.CompoundString("Force pause timeout after ")
+                            .append(alarm.getLastSetTimeout())
+                            .append("ms");
+            addLogs(log);
+            updatePaused(true /* isPaused */, log);
+        });
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
         mVelocityProvider = new SystemVelocityProvider(axis);
     }
@@ -113,8 +119,14 @@
      * @param disallowPause If true, we will not detect any pauses until this is set to false again.
      */
     public void setDisallowPause(boolean disallowPause) {
+        ActiveGestureLog.CompoundString log =
+                new ActiveGestureLog.CompoundString("Set disallowPause=")
+                        .append(disallowPause);
+        if (mDisallowPause != disallowPause) {
+            addLogs(log);
+        }
         mDisallowPause = disallowPause;
-        updatePaused(mIsPaused, "Set disallowPause=" + disallowPause);
+        updatePaused(mIsPaused, log);
     }
 
     /**
@@ -148,27 +160,30 @@
         float speed = Math.abs(velocity);
         float previousSpeed = Math.abs(prevVelocity);
         boolean isPaused;
-        String isPausedReason = "";
+        ActiveGestureLog.CompoundString isPausedReason;
         if (mIsPaused) {
             // Continue to be paused until moving at a fast speed.
             isPaused = speed < mSpeedFast || previousSpeed < mSpeedFast;
-            isPausedReason = "Was paused, but started moving at a fast speed";
+            isPausedReason = new ActiveGestureLog.CompoundString(
+                    "Was paused, but started moving at a fast speed");
         } else {
             if (velocity < 0 != prevVelocity < 0) {
                 // We're just changing directions, not necessarily stopping.
                 isPaused = false;
-                isPausedReason = "Velocity changed directions";
+                isPausedReason = new ActiveGestureLog.CompoundString("Velocity changed directions");
             } else {
                 isPaused = speed < mSpeedVerySlow && previousSpeed < mSpeedVerySlow;
-                isPausedReason = "Pause requires back to back slow speeds";
+                isPausedReason = new ActiveGestureLog.CompoundString(
+                        "Pause requires back to back slow speeds");
                 if (!isPaused && !mHasEverBeenPaused) {
                     // We want to be more aggressive about detecting the first pause to ensure it
                     // feels as responsive as possible; getting two very slow speeds back to back
                     // takes too long, so also check for a rapid deceleration.
                     boolean isRapidDeceleration = speed < previousSpeed * RAPID_DECELERATION_FACTOR;
                     isPaused = isRapidDeceleration && speed < mSpeedSomewhatFast;
-                    isPausedReason = "Didn't have back to back slow speeds, checking for rapid"
-                            + " deceleration on first pause only";
+                    isPausedReason = new ActiveGestureLog.CompoundString(
+                            "Didn't have back to back slow speeds, checking for rapid ")
+                            .append(" deceleration on first pause only");
                 }
                 if (mMakePauseHarderToTrigger) {
                     if (speed < mSpeedSlow) {
@@ -176,12 +191,14 @@
                             mSlowStartTime = time;
                         }
                         isPaused = time - mSlowStartTime >= HARDER_TRIGGER_TIMEOUT;
-                        isPausedReason = "Maintained slow speed for sufficient duration when making"
-                                + " pause harder to trigger";
+                        isPausedReason = new ActiveGestureLog.CompoundString(
+                                "Maintained slow speed for sufficient duration when making")
+                                .append(" pause harder to trigger");
                     } else {
                         mSlowStartTime = 0;
                         isPaused = false;
-                        isPausedReason = "Intentionally making pause harder to trigger";
+                        isPausedReason = new ActiveGestureLog.CompoundString(
+                                "Intentionally making pause harder to trigger");
                     }
                 }
             }
@@ -189,18 +206,21 @@
         updatePaused(isPaused, isPausedReason);
     }
 
-    private void updatePaused(boolean isPaused, String reason) {
+    private void updatePaused(boolean isPaused, ActiveGestureLog.CompoundString reason) {
         if (mDisallowPause) {
-            reason = "Disallow pause; otherwise, would have been " + isPaused + " due to " + reason;
+            reason = new ActiveGestureLog.CompoundString(
+                    "Disallow pause; otherwise, would have been ")
+                    .append(isPaused)
+                    .append(" due to reason:")
+                    .append(reason);
             isPaused = false;
         }
         if (mIsPaused != isPaused) {
             mIsPaused = isPaused;
-            String logString = "onMotionPauseChanged, paused=" + mIsPaused + " reason=" + reason;
-            if (Utilities.isRunningInTestHarness()) {
-                Log.d(TAG, logString);
-            }
-            ActiveGestureLog.INSTANCE.addLog(logString);
+            addLogs(new ActiveGestureLog.CompoundString("onMotionPauseChanged triggered; paused=")
+                    .append(mIsPaused)
+                    .append(", reason=")
+                    .append(reason));
             boolean isFirstDetectedPause = !mHasEverBeenPaused && mIsPaused;
             if (mIsPaused) {
                 AccessibilityManagerCompat.sendTestProtocolEventToTest(mContext,
@@ -219,6 +239,16 @@
         }
     }
 
+    private void addLogs(ActiveGestureLog.CompoundString compoundString) {
+        ActiveGestureLog.CompoundString logString =
+                new ActiveGestureLog.CompoundString("MotionPauseDetector: ")
+                        .append(compoundString);
+        if (Utilities.isRunningInTestHarness()) {
+            Log.d(TAG, logString.toString());
+        }
+        ActiveGestureLog.INSTANCE.addLog(logString);
+    }
+
     public void clear() {
         mVelocityProvider.clear();
         mPreviousVelocity = null;
diff --git a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
index 1c3c9c2..72fc2a6 100644
--- a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
+++ b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
@@ -18,6 +18,8 @@
 import android.animation.ValueAnimator;
 import android.view.animation.Interpolator;
 
+import com.android.launcher3.Utilities;
+
 import java.util.ArrayList;
 
 /**
@@ -31,14 +33,11 @@
     @Override
     public final void onAnimationUpdate(ValueAnimator animator) {
         final float percent = animator.getAnimatedFraction();
-        final float currentPlayTime = percent * animator.getDuration();
 
         for (int i = mAllProperties.size() - 1; i >= 0; i--) {
             FloatProp prop = mAllProperties.get(i);
-            float time = Math.max(0, currentPlayTime - prop.mDelay);
-            float newPercent = Math.min(1f, time / prop.mDuration);
-            newPercent = prop.mInterpolator.getInterpolation(newPercent);
-            prop.value = prop.mEnd * newPercent + prop.mStart * (1 - newPercent);
+            float interpolatedPercent = prop.mInterpolator.getInterpolation(percent);
+            prop.value = Utilities.mapRange(interpolatedPercent, prop.mStart, prop.mEnd);
         }
         onUpdate(percent, false /* initOnly */);
     }
@@ -55,17 +54,12 @@
 
         private final float mStart;
         private final float mEnd;
-        private final float mDelay;
-        private final float mDuration;
         private final Interpolator mInterpolator;
 
-        public FloatProp(float start, float end, float delay, float duration, Interpolator i) {
+        public FloatProp(float start, float end, Interpolator i) {
             value = mStart = start;
             mEnd = end;
-            mDelay = delay;
-            mDuration = duration;
             mInterpolator = i;
-
             mAllProperties.add(this);
         }
 
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 6d9ecd9..132d1c1 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -30,7 +30,7 @@
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.states.StateAnimationConfig;
 
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 
 /**
  * Runs an animation from overview to home. Currently, this animation is just a wrapper around the
@@ -44,14 +44,14 @@
     private final Launcher mLauncher;
     private final Runnable mOnReachedHome;
     @Nullable
-    private final Consumer<AnimatorSet> mSplitCancelConsumer;
+    private final BiConsumer<AnimatorSet, Long> mSplitCancelConsumer;
 
     // Only run mOnReachedHome when both of these are true.
     private boolean mIsHomeStaggeredAnimFinished;
     private boolean mIsOverviewHidden;
 
     public OverviewToHomeAnim(Launcher launcher, Runnable onReachedHome,
-            @Nullable Consumer<AnimatorSet> splitCancelConsumer) {
+            @Nullable BiConsumer<AnimatorSet, Long> splitCancelConsumer) {
         mLauncher = launcher;
         mOnReachedHome = onReachedHome;
         mSplitCancelConsumer = splitCancelConsumer;
@@ -103,7 +103,7 @@
 
         if (mSplitCancelConsumer != null) {
             // Clear split state when swiping to home
-            mSplitCancelConsumer.accept(anim);
+            mSplitCancelConsumer.accept(anim, config.duration);
         }
         anim.play(stateAnim);
         stateManager.setCurrentAnimation(anim, NORMAL);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 1d008da..0b05c2e 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -19,39 +19,40 @@
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
+import android.content.Context;
 
 import androidx.dynamicanimation.animation.DynamicAnimation;
 
 import com.android.launcher3.anim.SpringAnimationBuilder;
 import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 
-public class RecentsAtomicAnimationFactory<ACTIVITY_TYPE extends StatefulActivity, STATE_TYPE>
-        extends AtomicAnimationFactory<STATE_TYPE> {
+public class RecentsAtomicAnimationFactory<CONTAINER extends Context & RecentsViewContainer,
+        STATE_TYPE> extends AtomicAnimationFactory<STATE_TYPE> {
 
     public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
     public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
 
     private static final int MY_ANIM_COUNT = 2;
 
-    protected final ACTIVITY_TYPE mActivity;
+    protected final CONTAINER mContainer;
 
-    public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity) {
+    public RecentsAtomicAnimationFactory(CONTAINER container) {
         super(MY_ANIM_COUNT);
-        mActivity = activity;
+        mContainer = container;
     }
 
     @Override
     public Animator createStateElementAnimation(int index, float... values) {
         switch (index) {
             case INDEX_RECENTS_FADE_ANIM:
-                ObjectAnimator alpha = ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
+                ObjectAnimator alpha = ObjectAnimator.ofFloat(mContainer.getOverviewPanel(),
                         RecentsView.CONTENT_ALPHA, values);
                 return alpha;
             case INDEX_RECENTS_TRANSLATE_X_ANIM: {
-                RecentsView rv = mActivity.getOverviewPanel();
-                return new SpringAnimationBuilder(mActivity)
+                RecentsView rv = mContainer.getOverviewPanel();
+                return new SpringAnimationBuilder(mContainer)
                         .setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE)
                         .setDampingRatio(0.8f)
                         .setStiffness(250)
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index f6ad692..9335e7e 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -50,9 +50,10 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SettingsCache;
-import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 
 import java.lang.annotation.Retention;
 import java.util.function.IntConsumer;
@@ -75,7 +76,8 @@
     @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
     public @interface SurfaceRotation {}
 
-    private PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+    private RecentsPagedOrientationHandler mOrientationHandler =
+            RecentsPagedOrientationHandler.PORTRAIT;
 
     private @SurfaceRotation int mTouchRotation = ROTATION_0;
     private @SurfaceRotation int mDisplayRotation = ROTATION_0;
@@ -116,7 +118,7 @@
                     | FLAG_SWIPE_UP_NOT_RUNNING;
 
     private final Context mContext;
-    private final BaseActivityInterface mActivityInterface;
+    private final BaseContainerInterface mContainerInterface;
     private final OrientationEventListener mOrientationListener;
     private final SettingsCache mSettingsCache;
     private final SettingsCache.OnChangeListener mRotationChangeListener =
@@ -136,10 +138,10 @@
      *                              is enabled
      * @see #setRotationWatcherEnabled(boolean)
      */
-    public RecentsOrientedState(Context context, BaseActivityInterface activityInterface,
+    public RecentsOrientedState(Context context, BaseContainerInterface containerInterface,
             IntConsumer rotationChangeListener) {
         mContext = context;
-        mActivityInterface = activityInterface;
+        mContainerInterface = containerInterface;
         mOrientationListener = new OrientationEventListener(context) {
             @Override
             public void onOrientationChanged(int degrees) {
@@ -151,7 +153,7 @@
             }
         };
 
-        mFlags = mActivityInterface.rotationSupportedByActivity
+        mFlags = mContainerInterface.rotationSupportedByActivity
                 ? FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY : 0;
 
         mFlags |= FLAG_SWIPE_UP_NOT_RUNNING;
@@ -159,8 +161,8 @@
         initFlags();
     }
 
-    public BaseActivityInterface getActivityInterface() {
-        return mActivityInterface;
+    public BaseContainerInterface getContainerInterface() {
+        return mContainerInterface;
     }
 
     /**
@@ -225,13 +227,13 @@
     private boolean updateHandler() {
         mRecentsActivityRotation = inferRecentsActivityRotation(mDisplayRotation);
         if (mRecentsActivityRotation == mTouchRotation || isRecentsActivityRotationAllowed()) {
-            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+            mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT;
         } else if (mTouchRotation == ROTATION_90) {
-            mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
+            mOrientationHandler = RecentsPagedOrientationHandler.LANDSCAPE;
         } else if (mTouchRotation == ROTATION_270) {
-            mOrientationHandler = PagedOrientationHandler.SEASCAPE;
+            mOrientationHandler = RecentsPagedOrientationHandler.SEASCAPE;
         } else {
-            mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+            mOrientationHandler = RecentsPagedOrientationHandler.PORTRAIT;
         }
         if (DEBUG) {
             Log.d(TAG, "current RecentsOrientedState: " + this);
@@ -413,7 +415,7 @@
         return scale;
     }
 
-    public PagedOrientationHandler getOrientationHandler() {
+    public RecentsPagedOrientationHandler getOrientationHandler() {
         return mOrientationHandler;
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 251b756..5505bb3 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep.util;
 
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
+
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
 import android.animation.Animator;
@@ -104,6 +106,8 @@
     private float mCurrentScaleProgress;
     private FlingSpringAnim mRectXAnim;
     private FlingSpringAnim mRectYAnim;
+    private SpringAnimation mRectXSpring;
+    private SpringAnimation mRectYSpring;
     private SpringAnimation mRectScaleAnim;
     private boolean mAnimsStarted;
     private boolean mRectXAnimEnded;
@@ -166,27 +170,53 @@
     }
 
     public void onTargetPositionChanged() {
-        if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
-            mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
-        }
+        if (enableScalingRevealHomeAnimation()) {
+            if (isEnded()) {
+                return;
+            }
 
-        if (mRectYAnim != null) {
-            switch (mTracking) {
-                case TRACKING_TOP:
-                    if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
-                        mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
-                    }
-                    break;
-                case TRACKING_BOTTOM:
-                    if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
-                        mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
-                    }
-                    break;
-                case TRACKING_CENTER:
-                    if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
-                        mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
-                    }
-                    break;
+            if (mRectXSpring != null) {
+                mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
+                mRectXAnimEnded = false;
+            }
+
+            if (mRectYSpring != null) {
+                switch (mTracking) {
+                    case TRACKING_TOP:
+                        mRectYSpring.animateToFinalPosition(mTargetRect.top);
+                        break;
+                    case TRACKING_BOTTOM:
+                        mRectYSpring.animateToFinalPosition(mTargetRect.bottom);
+                        break;
+                    case TRACKING_CENTER:
+                        mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
+                        break;
+                }
+                mRectYAnimEnded = false;
+            }
+        } else {
+            if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
+                mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
+            }
+
+            if (mRectYAnim != null) {
+                switch (mTracking) {
+                    case TRACKING_TOP:
+                        if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
+                            mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
+                        }
+                        break;
+                    case TRACKING_BOTTOM:
+                        if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
+                            mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
+                        }
+                        break;
+                    case TRACKING_CENTER:
+                        if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
+                            mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
+                        }
+                        break;
+                }
             }
         }
     }
@@ -215,59 +245,127 @@
             maybeOnEnd();
         });
 
-        // We dampen the user velocity here to keep the natural feeling and to prevent the
-        // rect from straying too from a linear path.
-        final float xVelocityPxPerS = velocityPxPerMs.x * 1000;
-        final float yVelocityPxPerS = velocityPxPerMs.y * 1000;
-        final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
-                Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
-        final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
-                Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
-
+        float xVelocityPxPerS = velocityPxPerMs.x * 1000;
+        float yVelocityPxPerS = velocityPxPerMs.y * 1000;
         float startX = mCurrentCenterX;
         float endX = mTargetRect.centerX();
-        float minXValue = Math.min(startX, endX);
-        float maxXValue = Math.max(startX, endX);
-
-        mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
-                dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, mDampingX, mStiffnessX,
-                onXEndListener);
-
         float startY = mCurrentY;
         float endY = getTrackedYFromRect(mTargetRect);
-        float minYValue = Math.min(startY, endY);
-        float maxYValue = Math.max(startY, endY);
-        mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, dampedYVelocityPxPerS,
-                mMinVisChange, minYValue, maxYValue, mDampingY, mStiffnessY, onYEndListener);
-
         float minVisibleChange = Math.abs(1f / mStartRect.height());
-        ResourceProvider rp = DynamicResource.provider(context);
-        float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
 
-        // Increase the stiffness for devices where we want the window size to transform quicker.
-        boolean shouldUseHigherStiffness = profile != null
-                && (profile.isLandscape || profile.isTablet);
-        float stiffness = shouldUseHigherStiffness
-                ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
-                : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
+        if (enableScalingRevealHomeAnimation()) {
+            ResourceProvider rp = DynamicResource.provider(context);
+            long minVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_x_px_per_s);
+            long maxVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_x_px_per_s);
+            long minVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_y_px_per_s);
+            long maxVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_y_px_per_s);
+            float fallOffFactor = rp.getFloat(R.dimen.swipe_up_max_velocity_fall_off_factor);
 
-        mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
-                .setSpring(new SpringForce(1f)
-                .setDampingRatio(damping)
-                .setStiffness(stiffness))
-                .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
-                .setMaxValue(1f)
-                .setMinimumVisibleChange(minVisibleChange)
-                .addEndListener((animation, canceled, value, velocity) -> {
-                    mRectScaleAnimEnded = true;
-                    maybeOnEnd();
-                });
+            // We want the actual initial velocity to never dip below the minimum, and to taper off
+            // once it's above the soft cap so that we can prevent the window from flying off
+            // screen, while maintaining a natural feel.
+            xVelocityPxPerS = adjustVelocity(
+                    xVelocityPxPerS, minVelocityXPxPerS, maxVelocityXPxPerS, fallOffFactor);
+            yVelocityPxPerS = adjustVelocity(
+                    yVelocityPxPerS, minVelocityYPxPerS, maxVelocityYPxPerS, fallOffFactor);
 
-        setCanRelease(false);
-        mAnimsStarted = true;
+            float stiffnessX = rp.getFloat(R.dimen.swipe_up_rect_x_stiffness);
+            float dampingX = rp.getFloat(R.dimen.swipe_up_rect_x_damping_ratio);
+            mRectXSpring =
+                    new SpringAnimation(this, RECT_CENTER_X)
+                            .setSpring(
+                                    new SpringForce(endX)
+                                            .setStiffness(stiffnessX)
+                                            .setDampingRatio(dampingX)
+                            ).setStartValue(startX)
+                            .setStartVelocity(xVelocityPxPerS)
+                            .addEndListener(onXEndListener);
 
-        mRectXAnim.start();
-        mRectYAnim.start();
+            float stiffnessY = rp.getFloat(R.dimen.swipe_up_rect_y_stiffness);
+            float dampingY = rp.getFloat(R.dimen.swipe_up_rect_y_damping_ratio);
+            mRectYSpring =
+                    new SpringAnimation(this, RECT_Y)
+                            .setSpring(
+                                    new SpringForce(endY)
+                                            .setStiffness(stiffnessY)
+                                            .setDampingRatio(dampingY)
+                            )
+                            .setStartValue(startY)
+                            .setStartVelocity(yVelocityPxPerS)
+                            .addEndListener(onYEndListener);
+
+            float stiffnessZ = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness_v2);
+            float dampingZ = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio_v2);
+            mRectScaleAnim =
+                    new SpringAnimation(this, RECT_SCALE_PROGRESS)
+                            .setSpring(
+                                    new SpringForce(1f)
+                                            .setStiffness(stiffnessZ)
+                                            .setDampingRatio(dampingZ))
+                            .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+                            .setMaxValue(1f)
+                            .setMinimumVisibleChange(minVisibleChange)
+                            .addEndListener((animation, canceled, value, velocity) -> {
+                                mRectScaleAnimEnded = true;
+                                maybeOnEnd();
+                            });
+
+            setCanRelease(false);
+            mAnimsStarted = true;
+
+            mRectXSpring.start();
+            mRectYSpring.start();
+        } else {
+            // We dampen the user velocity here to keep the natural feeling and to prevent the
+            // rect from straying too from a linear path.
+            final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
+                    Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
+            final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
+                    Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
+
+            float minXValue = Math.min(startX, endX);
+            float maxXValue = Math.max(startX, endX);
+
+            mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
+                    dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, mDampingX,
+                    mStiffnessX, onXEndListener);
+
+            float minYValue = Math.min(startY, endY);
+            float maxYValue = Math.max(startY, endY);
+            mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY,
+                    dampedYVelocityPxPerS, mMinVisChange, minYValue, maxYValue, mDampingY,
+                    mStiffnessY, onYEndListener);
+
+            ResourceProvider rp = DynamicResource.provider(context);
+            float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
+
+            // Increase the stiffness for devices where we want the window size to transform
+            // quicker.
+            boolean shouldUseHigherStiffness = profile != null
+                    && (profile.isLandscape || profile.isTablet);
+            float stiffness = shouldUseHigherStiffness
+                    ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
+                    : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
+
+            mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
+                    .setSpring(new SpringForce(1f)
+                            .setDampingRatio(damping)
+                            .setStiffness(stiffness))
+                    .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+                    .setMaxValue(1f)
+                    .setMinimumVisibleChange(minVisibleChange)
+                    .addEndListener((animation, canceled, value, velocity) -> {
+                        mRectScaleAnimEnded = true;
+                        maybeOnEnd();
+                    });
+
+            setCanRelease(false);
+            mAnimsStarted = true;
+
+            mRectXAnim.start();
+            mRectYAnim.start();
+        }
+
         mRectScaleAnim.start();
         for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
             animatorListener.onAnimationStart(null);
@@ -276,12 +374,29 @@
 
     public void end() {
         if (mAnimsStarted) {
-            mRectXAnim.end();
-            mRectYAnim.end();
+            if (enableScalingRevealHomeAnimation()) {
+                if (mRectXSpring.canSkipToEnd()) {
+                    mRectXSpring.skipToEnd();
+                }
+                if (mRectYSpring.canSkipToEnd()) {
+                    mRectYSpring.skipToEnd();
+                }
+            } else {
+                mRectXAnim.end();
+                mRectYAnim.end();
+            }
             if (mRectScaleAnim.canSkipToEnd()) {
                 mRectScaleAnim.skipToEnd();
             }
+            mCurrentScaleProgress = mRectScaleAnim.getSpring().getFinalPosition();
+
+            // Ensures that we end the animation with the final values.
+            mRectXAnimEnded = false;
+            mRectYAnimEnded = false;
+            mRectScaleAnimEnded = false;
+            onUpdate();
         }
+
         mRectXAnimEnded = true;
         mRectYAnimEnded = true;
         mRectScaleAnimEnded = true;
@@ -349,6 +464,32 @@
         end();
     }
 
+    /**
+     * Modify the given velocity so that it's never below the minimum value, and falls off by the
+     * given factor once it goes above the maximum value.
+     * In order for the max soft cap to be enforced, the fall-off factor must be >1.
+     */
+    private static float adjustVelocity(float velocity, long min, long max, float factor) {
+        float sign = Math.signum(velocity);
+        float magnitude = Math.abs(velocity);
+
+        // If the absolute velocity is less than the min, bump it up.
+        if (magnitude < min) {
+            return min * sign;
+        }
+
+        // If the absolute velocity falls between min and max, or the fall-off factor is invalid,
+        // do nothing.
+        if (magnitude <= max || factor <= 1) {
+            return velocity;
+        }
+
+        // Scale the excess velocity by the fall-off factor.
+        float excess = magnitude - max;
+        float scaled = (float) Math.pow(excess, 1f / factor);
+        return (max + scaled) * sign;
+    }
+
     public interface OnUpdateListener {
         /**
          * Called when an update is made to the animation.
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
new file mode 100644
index 0000000..1bf77f1
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.graphics.Matrix
+import android.graphics.RectF
+import android.view.View
+import androidx.core.graphics.transform
+import com.android.app.animation.Interpolators
+import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.app.animation.Interpolators.LINEAR
+import com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE
+import com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.LauncherState
+import com.android.launcher3.anim.AnimatorListeners
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.anim.PropertySetter
+import com.android.launcher3.states.StateAnimationConfig
+import com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER
+import com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW
+import com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.quickstep.views.RecentsView
+
+/**
+ * Creates an animation where the workspace and hotseat fade in while revealing from the center of
+ * the screen outwards radially. This is used in conjunction with the swipe up to home animation.
+ */
+class ScalingWorkspaceRevealAnim(
+    launcher: QuickstepLauncher,
+    siblingAnimation: RectFSpringAnim?,
+    windowTargetRect: RectF?
+) {
+    companion object {
+        private const val FADE_DURATION_MS = 200L
+        private const val SCALE_DURATION_MS = 1000L
+        private const val MAX_ALPHA = 1f
+        private const val MIN_ALPHA = 0f
+        private const val MAX_SIZE = 1f
+        private const val MIN_SIZE = 0.85f
+    }
+
+    private val animation = PendingAnimation(SCALE_DURATION_MS)
+
+    init {
+        // Make sure the starting state is right for the animation.
+        val setupConfig = StateAnimationConfig()
+        setupConfig.animFlags = SKIP_OVERVIEW.or(SKIP_DEPTH_CONTROLLER).or(SKIP_SCRIM)
+        setupConfig.duration = 0
+        launcher.stateManager
+            .createAtomicAnimation(LauncherState.BACKGROUND_APP, LauncherState.NORMAL, setupConfig)
+            .start()
+        launcher
+            .getOverviewPanel<RecentsView<QuickstepLauncher, LauncherState>>()
+            .forceFinishScroller()
+        launcher.workspace.stateTransitionAnimation.setScrim(
+            PropertySetter.NO_ANIM_PROPERTY_SETTER,
+            LauncherState.BACKGROUND_APP,
+            setupConfig
+        )
+
+        val workspace = launcher.workspace
+        val hotseat = launcher.hotseat
+
+        // Scale the Workspace and Hotseat around the same pivot.
+        animation.addFloat(
+            workspace,
+            WORKSPACE_SCALE_PROPERTY_FACTORY[SCALE_INDEX_WORKSPACE_STATE],
+            MIN_SIZE,
+            MAX_SIZE,
+            EMPHASIZED,
+        )
+        workspace.setPivotToScaleWithSelf(hotseat)
+        animation.addFloat(
+            hotseat,
+            HOTSEAT_SCALE_PROPERTY_FACTORY[SCALE_INDEX_WORKSPACE_STATE],
+            MIN_SIZE,
+            MAX_SIZE,
+            EMPHASIZED,
+        )
+
+        // Fade in quickly at the beginning of the animation, so the content doesn't look like it's
+        // popping into existence out of nowhere.
+        val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
+        workspace.alpha = MIN_ALPHA
+        animation.setViewAlpha(
+            workspace,
+            MAX_ALPHA,
+            Interpolators.clampToProgress(LINEAR, 0f, fadeClamp)
+        )
+        hotseat.alpha = MIN_ALPHA
+        animation.setViewAlpha(
+            hotseat,
+            MAX_ALPHA,
+            Interpolators.clampToProgress(LINEAR, 0f, fadeClamp)
+        )
+
+        val transitionConfig = StateAnimationConfig()
+
+        // Match the Wallpaper animation to the rest of the content.
+        val depthController = (launcher as? QuickstepLauncher)?.depthController
+        transitionConfig.setInterpolator(StateAnimationConfig.ANIM_DEPTH, EMPHASIZED)
+        depthController?.setStateWithAnimation(LauncherState.NORMAL, transitionConfig, animation)
+
+        // Make sure that the contrast scrim animates correctly if needed.
+        transitionConfig.setInterpolator(StateAnimationConfig.ANIM_SCRIM_FADE, EMPHASIZED)
+        launcher.workspace.stateTransitionAnimation.setScrim(
+            animation,
+            LauncherState.NORMAL,
+            transitionConfig
+        )
+
+        // To avoid awkward jumps in icon position, we want the sibling animation to always be
+        // targeting the current position. Since we can't easily access this, instead we calculate
+        // it using the animation of the whole of home.
+        // We start by caching the final target position, as this is the base for the transforms.
+        val originalTarget = RectF(windowTargetRect)
+        animation.addOnFrameListener {
+            val transformed = RectF(originalTarget)
+
+            // First we scale down using the same pivot as the workspace scale, so we find the
+            // correct position AND size.
+            transformed.transform(
+                Matrix().apply {
+                    setScale(workspace.scaleX, workspace.scaleY, workspace.pivotX, workspace.pivotY)
+                }
+            )
+            // Then we scale back up around the center of the current position. This is because the
+            // icon animation behaves poorly if it is given a target that is smaller than the size
+            // of the icon.
+            transformed.transform(
+                Matrix().apply {
+                    setScale(
+                        1 / workspace.scaleX,
+                        1 / workspace.scaleY,
+                        transformed.centerX(),
+                        transformed.centerY()
+                    )
+                }
+            )
+
+            if (transformed != windowTargetRect) {
+                windowTargetRect?.set(transformed)
+                siblingAnimation?.onTargetPositionChanged()
+            }
+        }
+
+        // Needed to avoid text artefacts during the scale animation.
+        workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+        hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+        animation.addListener(
+            AnimatorListeners.forEndCallback(
+                Runnable {
+                    workspace.setLayerType(View.LAYER_TYPE_NONE, null)
+                    hotseat.setLayerType(View.LAYER_TYPE_NONE, null)
+                }
+            )
+        )
+    }
+
+    fun start() {
+        animation.buildAnim().start()
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt b/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt
new file mode 100644
index 0000000..dbeedd3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SlideInRemoteTransition.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import android.animation.TimeInterpolator
+import android.animation.ValueAnimator
+import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
+import android.graphics.Rect
+import android.os.IBinder
+import android.os.RemoteException
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.RemoteTransitionStub
+import android.window.TransitionInfo
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.Executors
+import com.android.wm.shell.shared.TransitionUtil
+
+/** Remote animation which slides the opening targets in and the closing targets out */
+class SlideInRemoteTransition(
+    private val isRtl: Boolean,
+    private val pageSpacing: Int,
+    private val cornerRadius: Float,
+    private val interpolator: TimeInterpolator,
+) : RemoteTransitionStub() {
+    private val animationDurationMs = 500L
+
+    override fun startAnimation(
+        transition: IBinder,
+        info: TransitionInfo,
+        startT: Transaction,
+        finishCB: IRemoteTransitionFinishedCallback
+    ) {
+        val anim = ValueAnimator.ofFloat(0f, 1f)
+        anim.interpolator = interpolator
+        anim.duration = animationDurationMs
+
+        val closingStartBounds: HashMap<SurfaceControl, Rect> = HashMap()
+        val openingEndBounds: HashMap<SurfaceControl, Rect> = HashMap()
+        for (chg in info.changes) {
+            val leash = chg.leash
+            startT.show(leash)
+
+            val taskInfo = chg.taskInfo
+            if (taskInfo?.activityType == ACTIVITY_TYPE_HOME || taskInfo?.parentTaskId != -1) {
+                continue
+            }
+            if (TransitionUtil.isClosingType(chg.mode)) {
+                closingStartBounds[leash] = chg.startAbsBounds
+                startT.setCrop(leash, chg.startAbsBounds).setCornerRadius(leash, cornerRadius)
+            }
+            if (TransitionUtil.isOpeningType(chg.mode)) {
+                openingEndBounds[leash] = chg.endAbsBounds
+                startT.setCrop(leash, chg.endAbsBounds).setCornerRadius(leash, cornerRadius)
+            }
+        }
+        startT.apply()
+
+        anim.addUpdateListener {
+            val t = Transaction()
+            closingStartBounds.keys.forEach {
+                // Translate the surface from its original position on-screen to off-screen on the
+                // right (or left in RTL)
+                val startBounds = closingStartBounds[it]
+                val targetX = (if (isRtl) -1 else 1) * (startBounds!!.right + pageSpacing)
+                t.setPosition(it, anim.animatedValue as Float * targetX, 0f)
+            }
+            openingEndBounds.keys.forEach {
+                // Set the alpha in the update listener to prevent one visible frame at the
+                // beginning
+                t.setAlpha(it, 1f)
+                // Translate the surface from off-screen on the left (or left in RTL) to its final
+                // position on-screen
+                val endBounds = openingEndBounds[it]
+                val targetX = (if (isRtl) -1 else 1) * (endBounds!!.right + pageSpacing)
+                t.setPosition(it, (1f - anim.animatedValue as Float) * -targetX, 0f)
+            }
+            t.apply()
+        }
+        anim.addListener(
+            forEndCallback(
+                Runnable {
+                    val t = Transaction()
+                    try {
+                        finishCB.onTransitionFinished(null, t)
+                    } catch (e: RemoteException) {
+                        // Ignore
+                    }
+                }
+            )
+        )
+
+        Executors.MAIN_EXECUTOR.execute { anim.start() }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index ade8074..021c455 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -23,6 +23,8 @@
 import android.animation.ObjectAnimator
 import android.animation.ValueAnimator
 import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW
+import android.content.Context
 import android.graphics.Bitmap
 import android.graphics.Rect
 import android.graphics.RectF
@@ -31,28 +33,37 @@
 import android.view.SurfaceControl
 import android.view.SurfaceControl.Transaction
 import android.view.View
-import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_OPEN
+import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.TransitionInfo
 import android.window.TransitionInfo.Change
+import android.window.WindowContainerToken
 import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators
 import com.android.launcher3.DeviceProfile
-import com.android.launcher3.Launcher
+import com.android.launcher3.Flags.enableOverviewIconMenu
+import com.android.launcher3.InsettableFrameLayout
 import com.android.launcher3.QuickstepTransitionManager
+import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.launcher3.anim.PendingAnimation
 import com.android.launcher3.apppairs.AppPairIcon
 import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.logging.StatsLogManager.EventEnum
 import com.android.launcher3.statehandlers.DepthController
 import com.android.launcher3.statemanager.StateManager
-import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
 import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.TaskViewUtils
 import com.android.quickstep.views.FloatingAppPairView
 import com.android.quickstep.views.FloatingTaskView
 import com.android.quickstep.views.GroupedTaskView
+import com.android.quickstep.views.IconAppChipView
 import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
 import com.android.quickstep.views.SplitInstructionsView
 import com.android.quickstep.views.TaskThumbnailView
 import com.android.quickstep.views.TaskView
@@ -62,69 +73,84 @@
 import java.util.function.Supplier
 
 /**
- * Utils class to help run animations for initiating split screen from launcher.
- * Will be expanded with future refactors. Works in conjunction with the state stored in
- * [SplitSelectStateController]
+ * Utils class to help run animations for initiating split screen from launcher. Will be expanded
+ * with future refactors. Works in conjunction with the state stored in [SplitSelectStateController]
  */
 class SplitAnimationController(val splitSelectStateController: SplitSelectStateController) {
     companion object {
         // Break this out into maybe enums? Abstractions into its own classes? Tbd.
         data class SplitAnimInitProps(
-                val originalView: View,
-                val originalBitmap: Bitmap?,
-                val iconDrawable: Drawable,
-                val fadeWithThumbnail: Boolean,
-                val isStagedTask: Boolean,
-                val iconView: View?
+            val originalView: View,
+            val originalBitmap: Bitmap?,
+            val iconDrawable: Drawable,
+            val fadeWithThumbnail: Boolean,
+            val isStagedTask: Boolean,
+            val iconView: View?
         )
     }
 
     /**
-     * Returns different elements to animate for the initial split selection animation
-     * depending on the state of the surface from which the split was initiated
+     * Returns different elements to animate for the initial split selection animation depending on
+     * the state of the surface from which the split was initiated
      */
-    fun getFirstAnimInitViews(taskViewSupplier: Supplier<TaskView>,
-                              splitSelectSourceSupplier: Supplier<SplitSelectSource?>)
-            : SplitAnimInitProps {
+    fun getFirstAnimInitViews(
+        taskViewSupplier: Supplier<TaskView>,
+        splitSelectSourceSupplier: Supplier<SplitSelectSource?>
+    ): SplitAnimInitProps {
         val splitSelectSource = splitSelectSourceSupplier.get()
         if (!splitSelectStateController.isAnimateCurrentTaskDismissal) {
             // Initiating from home
-            return SplitAnimInitProps(splitSelectSource!!.view, originalBitmap = null,
-                    splitSelectSource.drawable, fadeWithThumbnail = false, isStagedTask = true,
-                    iconView = null)
+            return SplitAnimInitProps(
+                splitSelectSource!!.view,
+                originalBitmap = null,
+                splitSelectSource.drawable,
+                fadeWithThumbnail = false,
+                isStagedTask = true,
+                iconView = null
+            )
         } else if (splitSelectStateController.isDismissingFromSplitPair) {
             // Initiating split from overview, but on a split pair
             val taskView = taskViewSupplier.get()
-            for (container : TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
+            for (container: TaskIdAttributeContainer in taskView.taskIdAttributeContainers) {
                 if (container.task.getKey().getId() == splitSelectStateController.initialTaskId) {
                     val drawable = getDrawable(container.iconView, splitSelectSource)
-                    return SplitAnimInitProps(container.thumbnailView,
-                            container.thumbnailView.thumbnail, drawable!!,
-                            fadeWithThumbnail = true, isStagedTask = true,
-                            iconView = container.iconView.asView()
+                    return SplitAnimInitProps(
+                        container.thumbnailView,
+                        container.thumbnailView.thumbnail,
+                        drawable!!,
+                        fadeWithThumbnail = true,
+                        isStagedTask = true,
+                        iconView = container.iconView.asView()
                     )
                 }
             }
-            throw IllegalStateException("Attempting to init split from existing split pair " +
-                    "without a valid taskIdAttributeContainer")
+            throw IllegalStateException(
+                "Attempting to init split from existing split pair " +
+                    "without a valid taskIdAttributeContainer"
+            )
         } else {
             // Initiating split from overview on fullscreen task TaskView
             val taskView = taskViewSupplier.get()
             val drawable = getDrawable(taskView.iconView, splitSelectSource)
-            return SplitAnimInitProps(taskView.thumbnail, taskView.thumbnail.thumbnail,
-                    drawable!!, fadeWithThumbnail = true, isStagedTask = true,
-                    taskView.iconView.asView()
+            return SplitAnimInitProps(
+                taskView.thumbnail,
+                taskView.thumbnail.thumbnail,
+                drawable!!,
+                fadeWithThumbnail = true,
+                isStagedTask = true,
+                taskView.iconView.asView()
             )
         }
     }
 
     /**
-     * Returns the drawable that's provided in iconView, however if that
-     * is null it falls back to the drawable that's in splitSelectSource.
-     * TaskView's icon drawable can be null if the TaskView is scrolled far enough off screen
+     * Returns the drawable that's provided in iconView, however if that is null it falls back to
+     * the drawable that's in splitSelectSource. TaskView's icon drawable can be null if the
+     * TaskView is scrolled far enough off screen
+     *
      * @return [Drawable]
      */
-    fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?) : Drawable? {
+    fun getDrawable(iconView: TaskViewIcon, splitSelectSource: SplitSelectSource?): Drawable? {
         if (iconView.drawable == null && splitSelectSource != null) {
             return splitSelectSource.drawable
         }
@@ -132,45 +158,76 @@
     }
 
     /**
-     * When selecting first app from split pair, second app's thumbnail remains. This animates
-     * the second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying
-     * it with [TaskThumbnailView]'s splashView. Adds animations to the provided builder.
-     * Note: The app that **was not** selected as the first split app should be the container that's
-     * passed through.
+     * When selecting first app from split pair, second app's thumbnail remains. This animates the
+     * second thumbnail by expanding it to take up the full taskViewWidth/Height and overlaying it
+     * with [TaskThumbnailView]'s splashView. Adds animations to the provided builder. Note: The app
+     * that **was not** selected as the first split app should be the container that's passed
+     * through.
      *
      * @param builder Adds animation to this
      * @param taskIdAttributeContainer container of the app that **was not** selected
      * @param isPrimaryTaskSplitting if true, task that was split would be top/left in the pair
-     *                               (opposite of that representing [taskIdAttributeContainer])
+     *   (opposite of that representing [taskIdAttributeContainer])
      */
-    fun addInitialSplitFromPair(taskIdAttributeContainer: TaskIdAttributeContainer,
-                                builder: PendingAnimation, deviceProfile: DeviceProfile,
-                                taskViewWidth: Int, taskViewHeight: Int,
-                                isPrimaryTaskSplitting: Boolean) {
+    fun addInitialSplitFromPair(
+        taskIdAttributeContainer: TaskIdAttributeContainer,
+        builder: PendingAnimation,
+        deviceProfile: DeviceProfile,
+        taskViewWidth: Int,
+        taskViewHeight: Int,
+        isPrimaryTaskSplitting: Boolean
+    ) {
         val thumbnail = taskIdAttributeContainer.thumbnailView
         val iconView: View = taskIdAttributeContainer.iconView.asView()
         builder.add(ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLASH_ALPHA, 1f))
         thumbnail.setShowSplashForSplitSelection(true)
+        // With the new `IconAppChipView`, we always want to keep the chip pinned to the
+        // top left of the task / thumbnail.
+        if (enableOverviewIconMenu()) {
+            builder.add(
+                ObjectAnimator.ofFloat(
+                    (iconView as IconAppChipView).splitTranslationX,
+                    MULTI_PROPERTY_VALUE,
+                    0f
+                )
+            )
+            builder.add(
+                ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f)
+            )
+        }
         if (deviceProfile.isLeftRightSplit) {
             // Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
             val centerThumbnailTranslationX: Float = (taskViewWidth - thumbnail.width) / 2f
-            val centerIconTranslationX: Float = (taskViewWidth - iconView.width) / 2f
             val finalScaleX: Float = taskViewWidth.toFloat() / thumbnail.width
-            builder.add(ObjectAnimator.ofFloat(thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, centerThumbnailTranslationX))
-            // icons are anchored from Gravity.END, so need to use negative translation
-            builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X,
-                    -centerIconTranslationX))
+            builder.add(
+                ObjectAnimator.ofFloat(
+                    thumbnail,
+                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X,
+                    centerThumbnailTranslationX
+                )
+            )
+            if (!enableOverviewIconMenu()) {
+                // icons are anchored from Gravity.END, so need to use negative translation
+                val centerIconTranslationX: Float = (taskViewWidth - iconView.width) / 2f
+                builder.add(
+                    ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, -centerIconTranslationX)
+                )
+            }
             builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_X, finalScaleX))
 
             // Reset other dimensions
             // TODO(b/271468547), can't set Y translate to 0, need to account for top space
             thumbnail.scaleY = 1f
-            val translateYResetVal: Float = if (!isPrimaryTaskSplitting) 0f else
-                deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
-            builder.add(ObjectAnimator.ofFloat(thumbnail,
+            val translateYResetVal: Float =
+                if (!isPrimaryTaskSplitting) 0f
+                else deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
+            builder.add(
+                ObjectAnimator.ofFloat(
+                    thumbnail,
                     TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
-                    translateYResetVal))
+                    translateYResetVal
+                )
+            )
         } else {
             val thumbnailSize = taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx
             // Center view first so scaling happens uniformly, alternatively we can move pivotY to 0
@@ -179,7 +236,6 @@
             // asymmetry causes problems..
 
             // Icon defaults to center | horizontal, we add additional translation for split
-            val centerIconTranslationX = 0f
             var centerThumbnailTranslationY: Float
 
             // TODO(b/271468547), primary thumbnail has layout margin above it, so secondary
@@ -187,130 +243,221 @@
             //  translations otherwise this asymmetry causes problems..
             if (isPrimaryTaskSplitting) {
                 centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
-                centerThumbnailTranslationY += deviceProfile.overviewTaskThumbnailTopMarginPx
-                        .toFloat()
+                centerThumbnailTranslationY +=
+                    deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
             } else {
                 centerThumbnailTranslationY = (thumbnailSize - thumbnail.height) / 2f
             }
             val finalScaleY: Float = thumbnailSize.toFloat() / thumbnail.height
-            builder.add(ObjectAnimator.ofFloat(thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y, centerThumbnailTranslationY))
+            builder.add(
+                ObjectAnimator.ofFloat(
+                    thumbnail,
+                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_Y,
+                    centerThumbnailTranslationY
+                )
+            )
 
-            // icons are anchored from Gravity.END, so need to use negative translation
-            builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X,
-                    centerIconTranslationX))
+            if (!enableOverviewIconMenu()) {
+                // icons are anchored from Gravity.END, so need to use negative translation
+                builder.add(ObjectAnimator.ofFloat(iconView, View.TRANSLATION_X, 0f))
+            }
             builder.add(ObjectAnimator.ofFloat(thumbnail, View.SCALE_Y, finalScaleY))
 
             // Reset other dimensions
             thumbnail.scaleX = 1f
-            builder.add(ObjectAnimator.ofFloat(thumbnail,
-                    TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f))
+            builder.add(
+                ObjectAnimator.ofFloat(thumbnail, TaskThumbnailView.SPLIT_SELECT_TRANSLATE_X, 0f)
+            )
         }
     }
 
+    /**
+     * Creates and returns a view to fade in at .4 animation progress and adds it to the provided
+     * [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
+     *
+     * [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
+     * screen, not the logical second app.
+     * For landscape it's the left app and for portrait the top one.
+     */
+    fun addDividerPlaceholderViewToAnim(pendingAnimation: PendingAnimation,
+                                        container: RecentsViewContainer,
+                                        secondPlaceholderEndingBounds: Rect,
+                                        context: Context) : View {
+        val mSplitDividerPlaceholderView = View(context)
+        val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
+        val dp : com.android.launcher3.DeviceProfile = container.getDeviceProfile()
+        // Add it before/under the most recently added first floating taskView
+        val firstAddedSplitViewIndex: Int = container.getDragLayer().indexOfChild(
+                recentsView.splitSelectController.firstFloatingTaskView)
+        container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
+        val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
+        lp.topMargin = 0
+
+        if (dp.isLeftRightSplit) {
+            lp.height = secondPlaceholderEndingBounds.height()
+            lp.width = container.asContext().resources.
+                getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+            mSplitDividerPlaceholderView.translationX = secondPlaceholderEndingBounds.right - lp.width / 2f
+            mSplitDividerPlaceholderView.translationY = 0f
+        } else {
+            lp.height = container.asContext().resources
+                    .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
+            lp.width = secondPlaceholderEndingBounds.width()
+            mSplitDividerPlaceholderView.translationY = secondPlaceholderEndingBounds.top - lp.height / 2f
+            mSplitDividerPlaceholderView.translationX = 0f
+        }
+
+        mSplitDividerPlaceholderView.alpha = 0f
+        mSplitDividerPlaceholderView.setBackgroundColor(container.asContext().resources
+                .getColor(R.color.taskbar_background_dark))
+        val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
+        pendingAnimation.setViewAlpha(mSplitDividerPlaceholderView, 1f,
+                Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f))
+        return mSplitDividerPlaceholderView
+    }
+
     /** Does not play any animation if user is not currently in split selection state. */
-    fun playPlaceholderDismissAnim(launcher: StatefulActivity<*>) {
+    fun playPlaceholderDismissAnim(container: RecentsViewContainer, splitDismissEvent: EventEnum) {
         if (!splitSelectStateController.isSplitSelectActive) {
             return
         }
 
-        val anim = createPlaceholderDismissAnim(launcher)
+        val anim = createPlaceholderDismissAnim(container, splitDismissEvent, null /*duration*/)
         anim.start()
     }
 
-    /** Returns [AnimatorSet] which slides initial split placeholder view offscreen. */
-    fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>) : AnimatorSet {
+    /**
+     * Returns [AnimatorSet] which slides initial split placeholder view offscreen and logs an event
+     * for why split is being dismissed
+     */
+    fun createPlaceholderDismissAnim(
+        container: RecentsViewContainer,
+        splitDismissEvent: EventEnum,
+        duration: Long?
+    ): AnimatorSet {
         val animatorSet = AnimatorSet()
-        val recentsView : RecentsView<*, *> = launcher.getOverviewPanel()
-        val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
-                ?: return animatorSet
+        duration?.let { animatorSet.duration = it }
+        val recentsView: RecentsView<*, *> = container.getOverviewPanel()
+        val floatingTask: FloatingTaskView =
+            splitSelectStateController.firstFloatingTaskView ?: return animatorSet
 
         // We are in split selection state currently, transitioning to another state
-        val dragLayer: BaseDragLayer<*> = launcher.dragLayer
+        val dragLayer: BaseDragLayer<*> = container.dragLayer
         val onScreenRectF = RectF()
-        Utilities.getBoundsForViewInDragLayer(dragLayer, floatingTask,
-                Rect(0, 0, floatingTask.width, floatingTask.height),
-                false, null, onScreenRectF)
+        Utilities.getBoundsForViewInDragLayer(
+            dragLayer,
+            floatingTask,
+            Rect(0, 0, floatingTask.width, floatingTask.height),
+            false,
+            null,
+            onScreenRectF
+        )
         // Get the part of the floatingTask that intersects with the DragLayer (i.e. the
         // on-screen portion)
         onScreenRectF.intersect(
-                dragLayer.left.toFloat(),
-                dragLayer.top.toFloat(),
-                dragLayer.right.toFloat(),
-                dragLayer.bottom
-                        .toFloat()
+            dragLayer.left.toFloat(),
+            dragLayer.top.toFloat(),
+            dragLayer.right.toFloat(),
+            dragLayer.bottom.toFloat()
         )
-        animatorSet.play(ObjectAnimator.ofFloat(floatingTask,
+        animatorSet.play(
+            ObjectAnimator.ofFloat(
+                floatingTask,
                 FloatingTaskView.PRIMARY_TRANSLATE_OFFSCREEN,
-                recentsView.pagedOrientationHandler
-                        .getFloatingTaskOffscreenTranslationTarget(
-                                floatingTask,
-                                onScreenRectF,
-                                floatingTask.stagePosition,
-                                launcher.deviceProfile
-                        )))
-        animatorSet.addListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator) {
-                splitSelectStateController.resetState()
-                safeRemoveViewFromDragLayer(launcher,
-                        splitSelectStateController.splitInstructionsView)
+                recentsView.pagedOrientationHandler.getFloatingTaskOffscreenTranslationTarget(
+                    floatingTask,
+                    onScreenRectF,
+                    floatingTask.stagePosition,
+                    container.deviceProfile
+                )
+            )
+        )
+        animatorSet.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    splitSelectStateController.resetState()
+                    safeRemoveViewFromDragLayer(
+                        container,
+                        splitSelectStateController.splitInstructionsView
+                    )
+                }
             }
-        })
+        )
+        splitSelectStateController.logExitReason(splitDismissEvent)
         return animatorSet
     }
 
     /**
-     * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second
-     * app for splitscreen
+     * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second app
+     * for splitscreen
      */
-    fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>) : PendingAnimation {
-        safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView)
-        val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher)
+    fun getShowSplitInstructionsAnim(container: RecentsViewContainer): PendingAnimation {
+        safeRemoveViewFromDragLayer(container, splitSelectStateController.splitInstructionsView)
+        val splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(container)
         splitSelectStateController.splitInstructionsView = splitInstructionsView
-        val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet)
+        val timings = AnimUtils.getDeviceOverviewToSplitTimings(container.deviceProfile.isTablet)
         val anim = PendingAnimation(100 /*duration */)
         splitInstructionsView.alpha = 0f
-        anim.setViewAlpha(splitInstructionsView, 1f,
-                Interpolators.clampToProgress(Interpolators.LINEAR,
-                        timings.instructionsContainerFadeInStartOffset,
-                        timings.instructionsContainerFadeInEndOffset))
-        anim.addFloat(splitInstructionsView, SplitInstructionsView.UNFOLD, 0.1f, 1f,
-                Interpolators.clampToProgress(Interpolators.EMPHASIZED_DECELERATE,
-                        timings.instructionsUnfoldStartOffset,
-                        timings.instructionsUnfoldEndOffset))
+        anim.setViewAlpha(
+            splitInstructionsView,
+            1f,
+            Interpolators.clampToProgress(
+                Interpolators.LINEAR,
+                timings.instructionsContainerFadeInStartOffset,
+                timings.instructionsContainerFadeInEndOffset
+            )
+        )
+        anim.addFloat(
+            splitInstructionsView,
+            SplitInstructionsView.UNFOLD,
+            0.1f,
+            1f,
+            Interpolators.clampToProgress(
+                Interpolators.EMPHASIZED_DECELERATE,
+                timings.instructionsUnfoldStartOffset,
+                timings.instructionsUnfoldEndOffset
+            )
+        )
         return anim
     }
 
     /** Removes the split instructions view from [launcher] drag layer. */
-    fun removeSplitInstructionsView(launcher: StatefulActivity<*>) {
-        safeRemoveViewFromDragLayer(launcher, splitSelectStateController.splitInstructionsView)
+    fun removeSplitInstructionsView(container: RecentsViewContainer) {
+        safeRemoveViewFromDragLayer(container, splitSelectStateController.splitInstructionsView)
     }
 
     /**
      * Animates the first placeholder view to fullscreen and launches its task.
+     *
      * TODO(b/276361926): Remove the [resetCallback] option once contextual launches
      */
-    fun playAnimPlaceholderToFullscreen(launcher: StatefulActivity<*>, view: View,
-                                        resetCallback: Optional<Runnable>) {
+    fun playAnimPlaceholderToFullscreen(
+        container: RecentsViewContainer,
+        view: View,
+        resetCallback: Optional<Runnable>
+    ) {
         val stagedTaskView = view as FloatingTaskView
 
-        val isTablet: Boolean = launcher.deviceProfile.isTablet
-        val duration = if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION else
-            SplitAnimationTimings.PHONE_CONFIRM_DURATION
+        val isTablet: Boolean = container.deviceProfile.isTablet
+        val duration =
+            if (isTablet) SplitAnimationTimings.TABLET_CONFIRM_DURATION
+            else SplitAnimationTimings.PHONE_CONFIRM_DURATION
+
         val pendingAnimation = PendingAnimation(duration.toLong())
         val firstTaskStartingBounds = Rect()
         val firstTaskEndingBounds = Rect()
 
         stagedTaskView.getBoundsOnScreen(firstTaskStartingBounds)
-        launcher.dragLayer.getBoundsOnScreen(firstTaskEndingBounds)
+        container.dragLayer.getBoundsOnScreen(firstTaskEndingBounds)
         splitSelectStateController.setLaunchingFirstAppFullscreen()
 
         stagedTaskView.addConfirmAnimation(
-                pendingAnimation,
-                RectF(firstTaskStartingBounds),
-                firstTaskEndingBounds,
-                false /* fadeWithThumbnail */,
-                true /* isStagedTask */)
+            pendingAnimation,
+            RectF(firstTaskStartingBounds),
+            firstTaskEndingBounds,
+            false /* fadeWithThumbnail */,
+            true /* isStagedTask */
+        )
 
         pendingAnimation.addEndListener {
             splitSelectStateController.launchInitialAppFullscreen {
@@ -387,14 +534,7 @@
                 "trying to launch an app pair icon, but encountered an unexpected null"
             }
 
-            composeIconSplitLaunchAnimator(
-                launchingIconView,
-                initialTaskId,
-                secondTaskId,
-                info,
-                t,
-                finishCallback
-            )
+            composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback)
         } else {
             // Fallback case: simple fade-in animation
             check(info != null && t != null) {
@@ -461,17 +601,44 @@
     /**
      * When the user taps an app pair icon to launch split, this will play the tasks' launch
      * animation from the position of the icon.
+     *
+     * To find the root shell leash that we want to fade in, we do the following: The Changes we
+     * receive in transitionInfo are structured like this
+     *
+     *     Root (grandparent)
+     *     |
+     *     |--> Split Root 1 (left/top side parent) (WINDOWING_MODE_MULTI_WINDOW)
+     *     |   |
+     *     |    --> App 1 (left/top side child) (WINDOWING_MODE_MULTI_WINDOW)
+     *     |--> Divider
+     *     |--> Split Root 2 (right/bottom side parent) (WINDOWING_MODE_MULTI_WINDOW)
+     *         |
+     *          --> App 2 (right/bottom side child) (WINDOWING_MODE_MULTI_WINDOW)
+     *
+     * We want to animate the Root (grandparent) so that it affects both apps and the divider. To do
+     * this, we find one of the nodes with WINDOWING_MODE_MULTI_WINDOW (one of the left-side ones,
+     * for simplicity) and traverse the tree until we find the grandparent.
+     *
+     * This function is only called when we are animating the app pair in from scratch. It is NOT
+     * called when we are animating in from an existing visible TaskView tile or an app that is
+     * already on screen.
      */
     @VisibleForTesting
     fun composeIconSplitLaunchAnimator(
         launchingIconView: AppPairIcon,
-        initialTaskId: Int,
-        secondTaskId: Int,
         transitionInfo: TransitionInfo,
         t: Transaction,
         finishCallback: Runnable
     ) {
-        val launcher = Launcher.getLauncher(launchingIconView.context)
+        // If launching an app pair from Taskbar inside of an app context (no access to Launcher),
+        // use the scale-up animation
+        if (launchingIconView.context is TaskbarActivityContext) {
+            composeScaleUpLaunchAnimation(transitionInfo, t, finishCallback)
+            return
+        }
+
+        // Else we are in Launcher and can launch with the full icon stretch-and-split animation.
+        val launcher = QuickstepLauncher.getLauncher(launchingIconView.context)
         val dp = launcher.deviceProfile
 
         // Create an AnimatorSet that will run both shell and launcher transitions together
@@ -481,46 +648,49 @@
         progressUpdater.setDuration(timings.getDuration().toLong())
         progressUpdater.interpolator = Interpolators.LINEAR
 
-        // Find the root shell leash that we want to fade in (parent of both app windows and
-        // the divider). For simplicity, we search using the initialTaskId.
-        var rootShellLayer: SurfaceControl? = null
-        var dividerPos = 0
+        var rootCandidate: Change? = null
 
         for (change in transitionInfo.changes) {
             val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
-            val taskId = taskInfo.taskId
-            val mode = change.mode
 
-            if (taskId == initialTaskId || taskId == secondTaskId) {
-                check(
-                    mode == WindowManager.TRANSIT_OPEN || mode == WindowManager.TRANSIT_TO_FRONT
-                ) {
-                    "Expected task to be showing, but it is $mode"
+            // TODO (b/316490565): Replace this logic when SplitBounds is available to
+            //  startAnimation() and we can know the precise taskIds of launching tasks.
+            // Find a change that has WINDOWING_MODE_MULTI_WINDOW.
+            if (
+                taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
+                    (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)
+            ) {
+                // Check if it is a left/top app.
+                val isLeftTopApp =
+                    (dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
+                        (!dp.isLeftRightSplit && change.endAbsBounds.top == 0)
+                if (isLeftTopApp) {
+                    // Found one!
+                    rootCandidate = change
+                    break
                 }
             }
-
-            if (taskId == initialTaskId) {
-                var splitRoot1 = change
-                val parentToken = change.parent
-                if (parentToken != null) {
-                    splitRoot1 = transitionInfo.getChange(parentToken) ?: change
-                }
-
-                val topLevelToken = splitRoot1.parent
-                if (topLevelToken != null) {
-                    rootShellLayer = transitionInfo.getChange(topLevelToken)?.leash
-                }
-
-                dividerPos =
-                    if (dp.isLeftRightSplit) change.endAbsBounds.right
-                    else change.endAbsBounds.bottom
-            }
         }
 
-        check(rootShellLayer != null) {
-            "Could not find a TransitionInfo.Change matching the initialTaskId"
+        // If we could not find a proper root candidate, something went wrong.
+        check(rootCandidate != null) { "Could not find a split root candidate" }
+
+        // Find the place where our left/top app window meets the divider (used for the
+        // launcher side animation)
+        val dividerPos =
+            if (dp.isLeftRightSplit) rootCandidate.endAbsBounds.right
+            else rootCandidate.endAbsBounds.bottom
+
+        // Recurse up the tree until parent is null, then we've found our root.
+        var parentToken: WindowContainerToken? = rootCandidate.parent
+        while (parentToken != null) {
+            rootCandidate = transitionInfo.getChange(parentToken) ?: break
+            parentToken = rootCandidate.parent
         }
 
+        // Make sure nothing weird happened, like getChange() returning null.
+        check(rootCandidate != null) { "Failed to find a root leash" }
+
         // Shell animation: the apps are revealed toward end of the launch animation
         progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
             val progress =
@@ -532,14 +702,14 @@
                 )
 
             // Set the alpha of the shell layer (2 apps + divider)
-            t.setAlpha(rootShellLayer, progress)
+            t.setAlpha(rootCandidate.leash, progress)
             t.apply()
         }
 
         // Create a new floating view in Launcher, positioned above the launching icon
         val drawableArea = launchingIconView.iconDrawableArea
-        val appIcon1 = launchingIconView.info.contents[0].newIcon(launchingIconView.context)
-        val appIcon2 = launchingIconView.info.contents[1].newIcon(launchingIconView.context)
+        val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
+        val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
         appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
         appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
         val floatingView =
@@ -550,6 +720,7 @@
                 appIcon2,
                 dividerPos
             )
+        floatingView.bringToFront()
 
         // Launcher animation: animate the floating view, expanding to fill the display surface
         progressUpdater.addUpdateListener(
@@ -558,8 +729,6 @@
                     FloatProp(
                         floatingView.startingPosition.left,
                         dp.widthPx / 2f - floatingView.startingPosition.width() / 2f,
-                        0f /* delay */,
-                        timings.getDuration().toFloat(),
                         Interpolators.clampToProgress(
                             timings.getStagedRectXInterpolator(),
                             timings.stagedRectSlideStartOffset,
@@ -570,8 +739,6 @@
                     FloatProp(
                         floatingView.startingPosition.top,
                         dp.heightPx / 2f - floatingView.startingPosition.height() / 2f,
-                        0f /* delay */,
-                        timings.getDuration().toFloat(),
                         Interpolators.clampToProgress(
                             Interpolators.EMPHASIZED,
                             timings.stagedRectSlideStartOffset,
@@ -582,8 +749,6 @@
                     FloatProp(
                         1f /* start */,
                         dp.widthPx / floatingView.startingPosition.width(),
-                        0f /* delay */,
-                        timings.getDuration().toFloat(),
                         Interpolators.clampToProgress(
                             Interpolators.EMPHASIZED,
                             timings.stagedRectSlideStartOffset,
@@ -594,8 +759,6 @@
                     FloatProp(
                         1f /* start */,
                         dp.heightPx / floatingView.startingPosition.height(),
-                        0f /* delay */,
-                        timings.getDuration().toFloat(),
                         Interpolators.clampToProgress(
                             Interpolators.EMPHASIZED,
                             timings.stagedRectSlideStartOffset,
@@ -629,6 +792,91 @@
     }
 
     /**
+     * This is a scale-up-and-fade-in animation (34% to 100%) for launching an app in Overview when
+     * there is no visible associated tile to expand from.
+     */
+    @VisibleForTesting
+    fun composeScaleUpLaunchAnimation(
+        transitionInfo: TransitionInfo,
+        t: Transaction,
+        finishCallback: Runnable
+    ) {
+        val launchAnimation = AnimatorSet()
+        val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
+        progressUpdater.setDuration(QuickstepTransitionManager.APP_LAUNCH_DURATION)
+        progressUpdater.interpolator = Interpolators.EMPHASIZED
+
+        var rootCandidate: Change? = null
+
+        for (change in transitionInfo.changes) {
+            val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+
+            // TODO (b/316490565): Replace this logic when SplitBounds is available to
+            //  startAnimation() and we can know the precise taskIds of launching tasks.
+            // Find a change that has WINDOWING_MODE_MULTI_WINDOW.
+            if (
+                taskInfo.windowingMode == WINDOWING_MODE_MULTI_WINDOW &&
+                    (change.mode == TRANSIT_OPEN || change.mode == TRANSIT_TO_FRONT)
+            ) {
+                // Found one!
+                rootCandidate = change
+                break
+            }
+        }
+
+        // If we could not find a proper root candidate, something went wrong.
+        check(rootCandidate != null) { "Could not find a split root candidate" }
+
+        // Recurse up the tree until parent is null, then we've found our root.
+        var parentToken: WindowContainerToken? = rootCandidate.parent
+        while (parentToken != null) {
+            rootCandidate = transitionInfo.getChange(parentToken) ?: break
+            parentToken = rootCandidate.parent
+        }
+
+        // Make sure nothing weird happened, like getChange() returning null.
+        check(rootCandidate != null) { "Failed to find a root leash" }
+
+        // Starting position is a 34% size tile centered in the middle of the screen.
+        // Ending position is the full device screen.
+        val screenBounds = rootCandidate.endAbsBounds
+        val startingScale = 0.34f
+        val startX =
+            screenBounds.left +
+                ((screenBounds.right - screenBounds.left) * ((1 - startingScale) / 2f))
+        val startY =
+            screenBounds.top +
+                ((screenBounds.bottom - screenBounds.top) * ((1 - startingScale) / 2f))
+        val endX = screenBounds.left
+        val endY = screenBounds.top
+
+        progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
+            val progress = valueAnimator.animatedFraction
+
+            val x = startX + ((endX - startX) * progress)
+            val y = startY + ((endY - startY) * progress)
+            val scale = startingScale + ((1 - startingScale) * progress)
+
+            t.setPosition(rootCandidate.leash, x, y)
+            t.setScale(rootCandidate.leash, scale, scale)
+            t.setAlpha(rootCandidate.leash, progress)
+            t.apply()
+        }
+
+        // When animation ends,  run finishCallback
+        progressUpdater.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    finishCallback.run()
+                }
+            }
+        )
+
+        launchAnimation.play(progressUpdater)
+        launchAnimation.start()
+    }
+
+    /**
      * If we are launching split screen without any special animation from a starting View, we
      * simply fade in the starting apps and fade out launcher.
      */
@@ -651,9 +899,7 @@
             // Find the target tasks' root tasks since those are the split stages that need to
             // be animated (the tasks themselves are children and thus inherit animation).
             if (taskId == initialTaskId || taskId == secondTaskId) {
-                check(
-                    mode == WindowManager.TRANSIT_OPEN || mode == WindowManager.TRANSIT_TO_FRONT
-                ) {
+                check(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
                     "Expected task to be showing, but it is $mode"
                 }
             }
@@ -683,11 +929,30 @@
             }
         }
 
+        if (splitRoot1 != null) {
+            // Set the highest level split root alpha; we could technically use the parent of
+            // either splitRoot1 or splitRoot2
+            val parentToken = splitRoot1.parent
+            var rootLayer: Change? = null
+            if (parentToken != null) {
+                rootLayer = transitionInfo.getChange(parentToken)
+            }
+            if (rootLayer != null && rootLayer.leash != null) {
+                openingTargets.add(rootLayer.leash)
+            }
+        }
+
         val animTransaction = Transaction()
         val animator = ValueAnimator.ofFloat(0f, 1f)
         animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
         animator.addUpdateListener { valueAnimator: ValueAnimator ->
-            val progress = valueAnimator.animatedFraction
+            val progress =
+                    Interpolators.clampToProgress(
+                            Interpolators.LINEAR,
+                            valueAnimator.animatedFraction,
+                            0.8f,
+                            1f
+                    )
             for (leash in openingTargets) {
                 animTransaction.setAlpha(leash, progress)
             }
@@ -709,26 +974,13 @@
             }
         )
 
-        if (splitRoot1 != null) {
-            // Set the highest level split root alpha; we could technically use the parent of
-            // either splitRoot1 or splitRoot2
-            val parentToken = splitRoot1.parent
-            var rootLayer: Change? = null
-            if (parentToken != null) {
-                rootLayer = transitionInfo.getChange(parentToken)
-            }
-            if (rootLayer != null && rootLayer.leash != null) {
-                t.setAlpha(rootLayer.leash, 1f)
-            }
-        }
-
         t.apply()
         animator.start()
     }
 
-    private fun safeRemoveViewFromDragLayer(launcher: StatefulActivity<*>, view: View?) {
+    private fun safeRemoveViewFromDragLayer(container: RecentsViewContainer, view: View?) {
         if (view != null) {
-            launcher.dragLayer.removeView(view)
+            container.dragLayer.removeView(view)
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index c013483..06edb14 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -87,6 +87,7 @@
     @StagePosition
     private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
     private var itemInfo: ItemInfo? = null
+    private var secondItemInfo: ItemInfo? = null
     private var splitEvent: EventEnum? = null
 
     private var initialTaskId: Int = INVALID_TASK_ID
@@ -144,8 +145,9 @@
      * To be called as soon as user selects the second task (even if animations aren't complete)
      * @param taskId The second task that will be launched.
      */
-    fun setSecondTask(taskId: Int) {
+    fun setSecondTask(taskId: Int, itemInfo: ItemInfo) {
         secondTaskId = taskId
+        secondItemInfo = itemInfo
     }
 
     /**
@@ -153,9 +155,10 @@
      * @param intent The second intent that will be launched.
      * @param user The user of that intent.
      */
-    fun setSecondTask(intent: Intent, user: UserHandle) {
+    fun setSecondTask(intent: Intent, user: UserHandle, itemInfo: ItemInfo) {
         secondIntent = intent
         secondUser = user
+        secondItemInfo = itemInfo
     }
 
     /**
@@ -163,9 +166,10 @@
      * Sets [secondUser] from that of the pendingIntent
      * @param pendingIntent The second PendingIntent that will be launched.
      */
-    fun setSecondTask(pendingIntent: PendingIntent) {
+    fun setSecondTask(pendingIntent: PendingIntent, itemInfo: ItemInfo) {
         secondPendingIntent = pendingIntent
         secondUser = pendingIntent.creatorUserHandle
+        secondItemInfo = itemInfo
     }
 
     /**
@@ -173,8 +177,8 @@
      * an extra intent from their RemoteResponse.
      * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
      */
-    fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?) {
-        setSecondTask(pendingIntent)
+    fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?, itemInfo: ItemInfo) {
+        setSecondTask(pendingIntent, itemInfo)
         widgetSecondIntent = widgetIntent
     }
 
@@ -407,6 +411,10 @@
         return itemInfo
     }
 
+    fun getSecondItemInfo(): ItemInfo? {
+        return secondItemInfo
+    }
+
     private fun isSecondTaskIntentSet(): Boolean {
         return secondTaskId != INVALID_TASK_ID || secondIntent != null
                 || secondPendingIntent != null
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d5899e4..c257be6 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -19,6 +19,10 @@
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_LEFT_TOP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTED_SECOND_APP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_COMPLETE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_INITIATED;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -31,7 +35,6 @@
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
@@ -60,15 +63,15 @@
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
-import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
 import android.window.RemoteTransition;
+import android.window.RemoteTransitionStub;
 import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.logging.InstanceId;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.apppairs.AppPairIcon;
@@ -78,9 +81,9 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.BackPressHandler;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -96,16 +99,18 @@
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
 import com.android.quickstep.views.SplitInstructionsView;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
 import com.android.wm.shell.splitscreen.ISplitSelectListener;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -116,7 +121,7 @@
 public class SplitSelectStateController {
     private static final String TAG = "SplitSelectStateCtor";
 
-    private StatefulActivity mContext;
+    private RecentsViewContainer mContainer;
     private final Handler mHandler;
     private final RecentsModel mRecentTasksModel;
     @Nullable
@@ -127,6 +132,7 @@
     private final StatsLogManager mStatsLogManager;
     private final SystemUiProxy mSystemUiProxy;
     private final StateManager mStateManager;
+    @Nullable
     private SplitFromDesktopController mSplitFromDesktopController;
     @Nullable
     private DepthController mDepthController;
@@ -147,10 +153,21 @@
     /** True when the first selected split app is being launched in fullscreen. */
     private boolean mLaunchingFirstAppFullscreen;
 
+    /**
+     * Should be a constant from {@link com.android.internal.jank.Cuj} or -1, does not need to be
+     * set for all launches.
+     */
+    private int mLaunchCuj = -1;
+
     private FloatingTaskView mFirstFloatingTaskView;
     private SplitInstructionsView mSplitInstructionsView;
 
     private final List<SplitSelectionListener> mSplitSelectionListeners = new ArrayList<>();
+    /**
+     * Tracks metrics from when first app is selected to split launch or cancellation. This also
+     * gets passed over to shell when attempting to invoke split.
+     */
+    private Pair<InstanceId, com.android.launcher3.logging.InstanceId> mSessionInstanceIds;
 
     private final BackPressHandler mSplitBackHandler = new BackPressHandler() {
         @Override
@@ -162,18 +179,19 @@
         public void onBackInvoked() {
             // When exiting from split selection, leave current context to go to
             // homescreen as well
-            getSplitAnimationController().playPlaceholderDismissAnim(mContext);
+            getSplitAnimationController().playPlaceholderDismissAnim(mContainer,
+                    LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
             if (mActivityBackCallback != null) {
                 mActivityBackCallback.run();
             }
         }
     };
 
-    public SplitSelectStateController(StatefulActivity context, Handler handler,
+    public SplitSelectStateController(RecentsViewContainer container, Handler handler,
             StateManager stateManager, DepthController depthController,
             StatsLogManager statsLogManager, SystemUiProxy systemUiProxy, RecentsModel recentsModel,
             Runnable activityBackCallback) {
-        mContext = context;
+        mContainer = container;
         mHandler = handler;
         mStatsLogManager = statsLogManager;
         mSystemUiProxy = systemUiProxy;
@@ -182,15 +200,18 @@
         mRecentTasksModel = recentsModel;
         mActivityBackCallback = activityBackCallback;
         mSplitAnimationController = new SplitAnimationController(this);
-        mAppPairsController = new AppPairsController(context, this, statsLogManager);
-        mSplitSelectDataHolder = new SplitSelectDataHolder(mContext);
+        mAppPairsController = new AppPairsController(mContainer.asContext(), this, statsLogManager);
+        mSplitSelectDataHolder = new SplitSelectDataHolder(mContainer.asContext());
     }
 
     public void onDestroy() {
-        mContext = null;
+        mContainer = null;
         mActivityBackCallback = null;
         mAppPairsController.onDestroy();
         mSplitSelectDataHolder.onDestroy();
+        if (mSplitFromDesktopController != null) {
+            mSplitFromDesktopController.onDestroy();
+        }
     }
 
     /**
@@ -203,6 +224,7 @@
             int alreadyRunningTask) {
         mSplitSelectDataHolder.setInitialTaskSelect(intent, stagePosition, itemInfo, splitEvent,
                 alreadyRunningTask);
+        createAndLogInstanceIdsForSession();
     }
 
     /**
@@ -213,6 +235,7 @@
             @StagePosition int stagePosition, @NonNull ItemInfo itemInfo,
             StatsLogManager.EventEnum splitEvent) {
         mSplitSelectDataHolder.setInitialTaskSelect(info, stagePosition, itemInfo, splitEvent);
+        createAndLogInstanceIdsForSession();
     }
 
     /**
@@ -225,14 +248,14 @@
      *                           tasks (i.e. searching for a running pair of tasks.)
      */
     public void findLastActiveTasksAndRunCallback(@Nullable List<ComponentKey> componentKeys,
-            boolean findExactPairMatch, Consumer<List<Task>> callback) {
+            boolean findExactPairMatch, Consumer<Task[]> callback) {
         mRecentTasksModel.getTasks(taskGroups -> {
             if (componentKeys == null || componentKeys.isEmpty()) {
-                callback.accept(Collections.emptyList());
+                callback.accept(new Task[]{});
                 return;
             }
 
-            List<Task> lastActiveTasks = new ArrayList<>();
+            Task[] lastActiveTasks = new Task[componentKeys.size()];
 
             if (findExactPairMatch) {
                 // Loop through tasks in reverse, since they are ordered with most-recent tasks last
@@ -240,32 +263,35 @@
                     GroupTask groupTask = taskGroups.get(i);
                     if (isInstanceOfAppPair(
                             groupTask, componentKeys.get(0), componentKeys.get(1))) {
-                        lastActiveTasks.add(groupTask.task1);
+                        lastActiveTasks[0] = groupTask.task1;
                         break;
                     }
                 }
             } else {
                 // For each key we are looking for, add to lastActiveTasks with the corresponding
                 // Task (or do nothing if not found).
-                for (ComponentKey key : componentKeys) {
+                for (int i = 0; i < componentKeys.size(); i++) {
+                    ComponentKey key = componentKeys.get(i);
                     Task lastActiveTask = null;
                     // Loop through tasks in reverse, since they are ordered with recent tasks last
-                    for (int i = taskGroups.size() - 1; i >= 0; i--) {
-                        GroupTask groupTask = taskGroups.get(i);
+                    for (int j = taskGroups.size() - 1; j >= 0; j--) {
+                        GroupTask groupTask = taskGroups.get(j);
                         Task task1 = groupTask.task1;
                         // Don't add duplicate Tasks
-                        if (isInstanceOfComponent(task1, key) && !lastActiveTasks.contains(task1)) {
+                        if (isInstanceOfComponent(task1, key)
+                                && !Arrays.asList(lastActiveTasks).contains(task1)) {
                             lastActiveTask = task1;
                             break;
                         }
                         Task task2 = groupTask.task2;
-                        if (isInstanceOfComponent(task2, key) && !lastActiveTasks.contains(task2)) {
+                        if (isInstanceOfComponent(task2, key)
+                                && !Arrays.asList(lastActiveTasks).contains(task2)) {
                             lastActiveTask = task2;
                             break;
                         }
                     }
 
-                    lastActiveTasks.add(lastActiveTask);
+                    lastActiveTasks[i] = lastActiveTask;
                 }
             }
 
@@ -327,14 +353,12 @@
      */
     public void launchSplitTasks(@PersistentSnapPosition int snapPosition,
             @Nullable Consumer<Boolean> callback) {
-        Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
-                LogUtils.getShellShareableInstanceId();
-        launchTasks(callback, false /* freezeTaskList */, snapPosition, instanceIds.first);
+        launchTasks(callback, false /* freezeTaskList */, snapPosition, mSessionInstanceIds.first);
 
         mStatsLogManager.logger()
-                .withItemInfo(mSplitSelectDataHolder.getItemInfo())
-                .withInstanceId(instanceIds.second)
-                .log(mSplitSelectDataHolder.getSplitEvent());
+                .withItemInfo(mSplitSelectDataHolder.getSecondItemInfo())
+                .withInstanceId(mSessionInstanceIds.second)
+                .log(LAUNCHER_SPLIT_SELECTED_SECOND_APP);
     }
 
     /**
@@ -361,11 +385,26 @@
     }
 
     /**
+     * Use to log an event when user exists split selection when the second app **IS NOT** selected.
+     * This must be called before playing any exit animations since most animations will call
+     * {@link #resetState()} which removes {@link #mSessionInstanceIds}.
+     */
+    public void logExitReason(StatsLogManager.EventEnum splitExitEvent) {
+        StatsLogManager.StatsLogger logger = mStatsLogManager.logger();
+        if (mSessionInstanceIds != null) {
+            logger.withInstanceId(mSessionInstanceIds.second);
+        } else {
+            Log.w(TAG, "Missing session instanceIds");
+        }
+        logger.log(splitExitEvent);
+    }
+
+    /**
      * To be called as soon as user selects the second task (even if animations aren't complete)
      * @param task The second task that will be launched.
      */
-    public void setSecondTask(Task task) {
-        mSplitSelectDataHolder.setSecondTask(task.key.id);
+    public void setSecondTask(Task task, ItemInfo itemInfo) {
+        mSplitSelectDataHolder.setSecondTask(task.key.id, itemInfo);
     }
 
     /**
@@ -373,20 +412,20 @@
      * @param intent The second intent that will be launched.
      * @param user The user of that intent.
      */
-    public void setSecondTask(Intent intent, UserHandle user) {
-        mSplitSelectDataHolder.setSecondTask(intent, user);
+    public void setSecondTask(Intent intent, UserHandle user, ItemInfo itemInfo) {
+        mSplitSelectDataHolder.setSecondTask(intent, user, itemInfo);
     }
 
     /**
      * To be called as soon as user selects the second app (even if animations aren't complete)
      * @param pendingIntent The second PendingIntent that will be launched.
      */
-    public void setSecondTask(PendingIntent pendingIntent) {
-        mSplitSelectDataHolder.setSecondTask(pendingIntent);
+    public void setSecondTask(PendingIntent pendingIntent, ItemInfo itemInfo) {
+        mSplitSelectDataHolder.setSecondTask(pendingIntent, itemInfo);
     }
 
     public void setSecondWidget(PendingIntent pendingIntent, Intent widgetIntent) {
-        mSplitSelectDataHolder.setSecondWidget(pendingIntent, widgetIntent);
+        mSplitSelectDataHolder.setSecondWidget(pendingIntent, widgetIntent, null /*itemInfo*/);
     }
 
     /**
@@ -495,6 +534,29 @@
     }
 
     /**
+     * Used to launch split screen from a split pair that already exists, optionally with a custom
+     * remote transition.
+     * <p>
+     * See {@link SplitSelectStateController#launchExistingSplitPair(
+     * GroupedTaskView, int, int, int, Consumer, boolean, int, RemoteTransition)}
+     */
+    public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
+            int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
+            Consumer<Boolean> callback, boolean freezeTaskList,
+            @PersistentSnapPosition int snapPosition) {
+        launchExistingSplitPair(
+                groupedTaskView,
+                firstTaskId,
+                secondTaskId,
+                stagePosition,
+                callback,
+                freezeTaskList,
+                snapPosition,
+                /* remoteTransition= */ null);
+    }
+
+
+    /**
      * Used to launch split screen from a split pair that already exists (usually accessible through
      * Overview). This is different than {@link #launchTasks(Consumer, boolean, int, InstanceId)}
      * in that this only launches split screen that are existing tasks. This doesn't determine which
@@ -506,7 +568,7 @@
     public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
             int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
             Consumer<Boolean> callback, boolean freezeTaskList,
-            @PersistentSnapPosition int snapPosition) {
+            @PersistentSnapPosition int snapPosition, @Nullable RemoteTransition remoteTransition) {
         mLaunchingTaskView = groupedTaskView;
         final ActivityOptions options1 = ActivityOptions.makeBasic();
         if (freezeTaskList) {
@@ -515,10 +577,12 @@
         Bundle optionsBundle = options1.toBundle();
 
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
-                    secondTaskId, callback, "LaunchExistingPair");
+            final RemoteTransition transition = remoteTransition == null
+                    ? getShellRemoteTransition(
+                            firstTaskId, secondTaskId, callback, "LaunchExistingPair")
+                    : remoteTransition;
             mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
-                    stagePosition, snapPosition, remoteTransition, null /*shellInstanceId*/);
+                    stagePosition, snapPosition, transition, null /*shellInstanceId*/);
         } else {
             final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
                     secondTaskId, callback);
@@ -550,7 +614,7 @@
         final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
                 ActivityThread.currentActivityThread().getApplicationThread(),
                 "LaunchAppFullscreen");
-        InstanceId instanceId = LogUtils.getShellShareableInstanceId().first;
+        InstanceId instanceId = mSessionInstanceIds.first;
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
@@ -582,8 +646,13 @@
         }
     }
 
-    public void initSplitFromDesktopController(Launcher launcher) {
-        mSplitFromDesktopController = new SplitFromDesktopController(launcher);
+    public void initSplitFromDesktopController(QuickstepLauncher launcher) {
+        initSplitFromDesktopController(new SplitFromDesktopController(launcher));
+    }
+
+    @VisibleForTesting
+    void initSplitFromDesktopController(SplitFromDesktopController controller) {
+        mSplitFromDesktopController = controller;
     }
 
     private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
@@ -602,6 +671,26 @@
                 ActivityThread.currentActivityThread().getApplicationThread());
     }
 
+    /**
+     * Will initialize {@link #mSessionInstanceIds} if null and log the first split event from
+     * {@link #mSplitSelectDataHolder}
+     */
+    private void createAndLogInstanceIdsForSession() {
+        if (mSessionInstanceIds != null) {
+            Log.w(TAG, "SessionIds should be null");
+        }
+        // Log separately the start of the session and then the first app selected
+        mSessionInstanceIds = LogUtils.getShellShareableInstanceId();
+        mStatsLogManager.logger()
+                .withInstanceId(mSessionInstanceIds.second)
+                .log(LAUNCHER_SPLIT_SELECTION_INITIATED);
+
+        mStatsLogManager.logger()
+                .withItemInfo(mSplitSelectDataHolder.getItemInfo())
+                .withInstanceId(mSessionInstanceIds.second)
+                .log(mSplitSelectDataHolder.getSplitEvent());
+    }
+
     public @StagePosition int getActiveSplitStagePosition() {
         return mSplitSelectDataHolder.getInitialStagePosition();
     }
@@ -634,10 +723,14 @@
         return mSplitAnimationController;
     }
 
+    public void setLaunchingCuj(int launchCuj) {
+        mLaunchCuj = launchCuj;
+    }
+
     /**
      * Requires Shell Transitions
      */
-    private class RemoteSplitLaunchTransitionRunner extends IRemoteTransition.Stub {
+    private class RemoteSplitLaunchTransitionRunner extends RemoteTransitionStub {
 
         private final int mInitialTaskId;
         private final int mSecondTaskId;
@@ -664,8 +757,10 @@
 
             MAIN_EXECUTOR.execute(() -> {
                 // Only animate from taskView if it's already visible
-                boolean shouldLaunchFromTaskView = mLaunchingTaskView != null &&
-                        mLaunchingTaskView.getRecentsView().isTaskViewVisible(mLaunchingTaskView);
+                boolean shouldLaunchFromTaskView = mLaunchingTaskView != null
+                        && mLaunchingTaskView.getRecentsView() != null
+                        && mLaunchingTaskView.getRecentsView().isTaskViewVisible(
+                        mLaunchingTaskView);
                 mSplitAnimationController.playSplitLaunchAnimation(
                         shouldLaunchFromTaskView ? mLaunchingTaskView : null,
                         mLaunchingIconView,
@@ -684,11 +779,6 @@
         }
 
         @Override
-        public void mergeAnimation(IBinder transition, TransitionInfo info,
-                SurfaceControl.Transaction t, IBinder mergeTarget,
-                IRemoteTransitionFinishedCallback finishedCallback) { }
-
-        @Override
         public void onTransitionConsumed(IBinder transition, boolean aborted)
                 throws RemoteException {
             MAIN_EXECUTOR.execute(() -> {
@@ -774,6 +864,18 @@
         mFirstFloatingTaskView = null;
         mSplitInstructionsView = null;
         mLaunchingFirstAppFullscreen = false;
+
+        if (mLaunchCuj != -1) {
+            InteractionJankMonitorWrapper.end(mLaunchCuj);
+        }
+        mLaunchCuj = -1;
+
+        if (mSessionInstanceIds != null) {
+            mStatsLogManager.logger()
+                    .withInstanceId(mSessionInstanceIds.second)
+                    .log(LAUNCHER_SPLIT_SELECTION_COMPLETE);
+        }
+        mSessionInstanceIds = null;
     }
 
     /**
@@ -846,7 +948,7 @@
     public class SplitFromDesktopController {
         private static final String TAG = "SplitFromDesktopController";
 
-        private final Launcher mLauncher;
+        private final QuickstepLauncher mLauncher;
         private final OverviewComponentObserver mOverviewComponentObserver;
         private final int mSplitPlaceholderSize;
         private final int mSplitPlaceholderInset;
@@ -854,7 +956,7 @@
         private ISplitSelectListener mSplitSelectListener;
         private Drawable mAppIcon;
 
-        public SplitFromDesktopController(Launcher launcher) {
+        public SplitFromDesktopController(QuickstepLauncher launcher) {
             mLauncher = launcher;
             RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
                     launcher.getApplicationContext());
@@ -868,7 +970,6 @@
                 @Override
                 public boolean onRequestSplitSelect(ActivityManager.RunningTaskInfo taskInfo,
                         int splitPosition, Rect taskBounds) {
-                    if (!isDesktopModeSupported()) return false;
                     MAIN_EXECUTOR.execute(() -> enterSplitSelect(taskInfo, splitPosition,
                             taskBounds));
                     return true;
@@ -877,6 +978,11 @@
             SystemUiProxy.INSTANCE.get(mLauncher).registerSplitSelectListener(mSplitSelectListener);
         }
 
+        void onDestroy() {
+            SystemUiProxy.INSTANCE.get(mLauncher).unregisterSplitSelectListener(
+                    mSplitSelectListener);
+        }
+
         /**
          * Enter split select from desktop mode.
          * @param taskInfo the desktop task to move to split stage
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index e705285..2396512 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -17,7 +17,6 @@
 package com.android.quickstep.util;
 
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -34,16 +33,19 @@
 import android.os.UserHandle;
 import android.view.View;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@@ -51,16 +53,17 @@
 /** Handles when the stage split lands on the home screen. */
 public class SplitToWorkspaceController {
 
-    private final Launcher mLauncher;
+    private final QuickstepLauncher mLauncher;
     private final SplitSelectStateController mController;
 
     private final int mHalfDividerSize;
     private final IconCache mIconCache;
 
-    public SplitToWorkspaceController(Launcher launcher, SplitSelectStateController controller) {
+    public SplitToWorkspaceController(QuickstepLauncher launcher,
+            SplitSelectStateController controller) {
         mLauncher = launcher;
         mController = controller;
-        mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache();
+        mIconCache = LauncherAppState.getInstance(launcher).getIconCache();
         mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.multi_window_task_divider_size) / 2;
     }
@@ -122,11 +125,16 @@
             intent = appInfo.intent;
             user = appInfo.user;
             bitmapInfo = appInfo.bitmap;
+        } else if (tag instanceof AppPairInfo) {
+            // Prompt the user to select something else by wiggling the instructions view
+            mController.getSplitInstructionsView().goBoing();
+            return true;
         } else {
+            // Use Launcher's default click handler
             return false;
         }
 
-        mController.setSecondTask(intent, user);
+        mController.setSecondTask(intent, user, (ItemInfo) tag);
 
         startWorkspaceAnimation(view, null /*bitmap*/, bitmapInfo.newIcon(mLauncher));
         return true;
@@ -155,6 +163,10 @@
                 new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
                 false /* fadeWithThumbnail */, true /* isStagedTask */);
 
+        View mSplitDividerPlaceholderView = recentsView.getSplitSelectController()
+                .getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
+                        mLauncher, secondTaskEndingBounds, view.getContext());
+
         FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher,
                 view, bitmap, icon, secondTaskStartingBounds);
         secondFloatingTaskView.setAlpha(1);
@@ -165,6 +177,11 @@
             private boolean mIsCancelled = false;
 
             @Override
+            public void onAnimationStart(Animator animation) {
+                mController.launchSplitTasks(aBoolean -> cleanUp());
+            }
+
+            @Override
             public void onAnimationCancel(Animator animation) {
                 mIsCancelled = true;
                 cleanUp();
@@ -173,15 +190,14 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (!mIsCancelled) {
-                    mController.launchSplitTasks(aBoolean -> cleanUp());
-                    InteractionJankMonitorWrapper.end(
-                            InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+                    InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
                 }
             }
 
             private void cleanUp() {
                 mLauncher.getDragLayer().removeView(firstFloatingTaskView);
                 mLauncher.getDragLayer().removeView(secondFloatingTaskView);
+                mLauncher.getDragLayer().removeView(mSplitDividerPlaceholderView);
                 mController.getSplitAnimationController().removeSplitInstructionsView(mLauncher);
                 mController.resetState();
             }
@@ -190,8 +206,6 @@
     }
 
     private boolean shouldIgnoreSecondSplitLaunch() {
-        return (!FeatureFlags.enableSplitContextually()
-                && !isDesktopModeSupported())
-                || !mController.isSplitSelectActive();
+        return !FeatureFlags.enableSplitContextually() || !mController.isSplitSelectActive();
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index cb32c6c..555bf21 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -35,6 +35,7 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.OverviewComponentObserver;
 import com.android.quickstep.RecentsAnimationCallbacks;
@@ -43,6 +44,7 @@
 import com.android.quickstep.RecentsAnimationTargets;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.recents.model.Task;
@@ -53,6 +55,7 @@
 
     private final QuickstepLauncher mLauncher;
     private final SplitSelectStateController mController;
+    private final RecentsAnimationDeviceState mDeviceState;
     private final OverviewComponentObserver mOverviewComponentObserver;
 
     private final int mSplitPlaceholderSize;
@@ -62,10 +65,9 @@
             SplitSelectStateController controller) {
         mLauncher = launcher;
         mController = controller;
-        RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(
-                launcher.getApplicationContext());
+        mDeviceState = new RecentsAnimationDeviceState(launcher.getApplicationContext());
         mOverviewComponentObserver = new OverviewComponentObserver(launcher.getApplicationContext(),
-                deviceState);
+                mDeviceState);
 
         mSplitPlaceholderSize = mLauncher.getResources().getDimensionPixelSize(
                 R.dimen.split_placeholder_size);
@@ -75,7 +77,9 @@
 
     @BinderThread
     public void enterStageSplit(boolean leftOrTop) {
-        if (!enableSplitContextually()) {
+        if (!enableSplitContextually() ||
+                // Do not enter stage split from keyboard shortcuts if the user is already in split
+                TopTaskTracker.INSTANCE.get(mLauncher).getRunningSplitTaskIds().length == 2) {
             return;
         }
         RecentsAnimationCallbacks callbacks = new RecentsAnimationCallbacks(
@@ -97,6 +101,7 @@
 
     public void onDestroy() {
         mOverviewComponentObserver.onDestroy();
+        mDeviceState.destroy();
     }
 
     private class SplitWithKeyboardShortcutRecentsAnimationListener implements
@@ -146,10 +151,29 @@
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationStart(Animator animation) {
-                    controller.finish(true /* toRecents */, null /* onFinishComplete */,
+                    controller.finish(
+                            true /* toRecents */,
+                            () -> {
+                                LauncherTaskbarUIController controller =
+                                        mLauncher.getTaskbarUIController();
+                                if (controller != null) {
+                                    controller.updateTaskbarLauncherStateGoingHome();
+                                }
+
+                            },
                             false /* sendUserLeaveHint */);
                 }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    mLauncher.getDragLayer().removeView(floatingTaskView);
+                    mController.getSplitAnimationController()
+                            .removeSplitInstructionsView(mLauncher);
+                    mController.resetState();
+                }
             });
+            anim.add(mController.getSplitAnimationController()
+                    .getShowSplitInstructionsAnim(mLauncher).buildAnim());
             anim.buildAnim().start();
         }
     };
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 6b3199f..997a842 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -38,7 +38,6 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
@@ -65,7 +64,7 @@
     // Should be used for animations running alongside this StaggeredWorkspaceAnim.
     public static final int DURATION_MS = 250;
     public static final int DURATION_TASKBAR_MS =
-            QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
+            QuickstepTransitionManager.getTaskbarToHomeDuration();
 
     private static final float MAX_VELOCITY_PX_PER_S = 22f;
 
@@ -75,13 +74,13 @@
     private final AnimatorSet mAnimators = new AnimatorSet();
     private final @Nullable View mIgnoredView;
 
-    public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim,
-            @Nullable View ignoredView) {
+    public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity,
+            boolean animateOverviewScrim, @Nullable View ignoredView) {
         this(launcher, velocity, animateOverviewScrim, ignoredView, true);
     }
 
-    public StaggeredWorkspaceAnim(Launcher launcher, float velocity, boolean animateOverviewScrim,
-            @Nullable View ignoredView, boolean staggerWorkspace) {
+    public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity,
+            boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) {
         prepareToAnimate(launcher, animateOverviewScrim);
 
         mIgnoredView = ignoredView;
@@ -124,7 +123,8 @@
                 for (int i = hotseatIcons.getChildCount() - 1; i >= 0; i--) {
                     View child = hotseatIcons.getChildAt(i);
                     CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams());
-                    addStaggeredAnimationForView(child, lp.getCellY() + 1, totalRows, duration);
+                    addStaggeredAnimationForView(child, lp.getCellY() + 1,
+                            totalRows, duration);
                 }
             } else {
                 final int hotseatRow, qsbRow;
@@ -194,7 +194,8 @@
         for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) {
             View child = itemsContainer.getChildAt(i);
             CellLayoutLayoutParams lp = ((CellLayoutLayoutParams) child.getLayoutParams());
-            addStaggeredAnimationForView(child, lp.getCellY() + lp.cellVSpan, totalRows, duration);
+            addStaggeredAnimationForView(child, lp.getCellY() + lp.cellVSpan,
+                    totalRows, duration);
         }
 
         mAnimators.addListener(new AnimatorListenerAdapter() {
@@ -209,7 +210,7 @@
     /**
      * Setup workspace with 0 duration to prepare for our staggered animation.
      */
-    private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
+    private void prepareToAnimate(QuickstepLauncher launcher, boolean animateOverviewScrim) {
         StateAnimationConfig config = new StateAnimationConfig();
         config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER | SKIP_SCRIM;
         config.duration = 0;
@@ -294,12 +295,10 @@
         mAnimators.play(alpha);
     }
 
-    private void addDepthAnimationForState(Launcher launcher, LauncherState state, long duration) {
-        if (!(launcher instanceof QuickstepLauncher)) {
-            return;
-        }
+    private void addDepthAnimationForState(QuickstepLauncher launcher, LauncherState state,
+            long duration) {
         PendingAnimation builder = new PendingAnimation(duration);
-        DepthController depthController = ((QuickstepLauncher) launcher).getDepthController();
+        DepthController depthController = launcher.getDepthController();
         depthController.setStateWithAnimation(state, new StateAnimationConfig(), builder);
         mAnimators.play(builder.buildAnim());
     }
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
index df5765c..a26d056 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -15,8 +15,6 @@
  */
 package com.android.quickstep.util;
 
-import android.annotation.TargetApi;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Message;
 import android.view.SurfaceControl;
@@ -34,7 +32,6 @@
  *   android.view.SyncRtSurfaceTransactionApplier
  * with some Launcher specific utility methods
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class SurfaceTransactionApplier extends ReleaseCheck {
 
     private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index fe6ce46..f823aff 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -16,8 +16,6 @@
 
 package com.android.quickstep.util;
 
-import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_PIP;
-
 import android.animation.Animator;
 import android.animation.RectEvaluator;
 import android.content.ComponentName;
@@ -35,6 +33,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.icons.IconProvider;
 import com.android.quickstep.TaskAnimationManager;
@@ -113,7 +112,7 @@
             @NonNull ActivityInfo activityInfo,
             int appIconSizePx,
             @NonNull SurfaceControl leash,
-            @Nullable Rect sourceRectHint,
+            @NonNull Rect sourceRectHint,
             @NonNull Rect appBounds,
             @NonNull Matrix homeToWindowPositionMap,
             @NonNull RectF startBounds,
@@ -136,22 +135,25 @@
         mDestinationBoundsTransformed.set(destinationBoundsTransformed);
         mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(cornerRadius, shadowRadius);
 
-        if (sourceRectHint != null && (sourceRectHint.width() < destinationBounds.width()
-                || sourceRectHint.height() < destinationBounds.height())) {
+        String reasonForCreateOverlay = null; // For debugging purpose.
+        if (sourceRectHint.isEmpty()) {
+            reasonForCreateOverlay = "Source rect hint is empty";
+        } else if (sourceRectHint.width() < destinationBounds.width()
+                || sourceRectHint.height() < destinationBounds.height()) {
             // This is a situation in which the source hint rect on at least one axis is smaller
             // than the destination bounds, which presents a problem because we would have to scale
             // up that axis to fit the bounds. So instead, just fallback to the non-source hint
             // animation in this case.
-            sourceRectHint = null;
-        }
-
-        if (sourceRectHint != null && !appBounds.contains(sourceRectHint)) {
+            reasonForCreateOverlay = "Source rect hint is too small " + sourceRectHint;
+            sourceRectHint.setEmpty();
+        } else if (!appBounds.contains(sourceRectHint)) {
             // This is a situation in which the source hint rect is outside the app bounds, so it is
             // not a valid rectangle to use for cropping app surface
-            sourceRectHint = null;
+            sourceRectHint.setEmpty();
+            reasonForCreateOverlay = "Source rect hint exceeds display bounds " + sourceRectHint;
         }
 
-        if (sourceRectHint == null) {
+        if (sourceRectHint.isEmpty()) {
             mSourceRectHint.setEmpty();
             mSourceHintRectInsets = null;
 
@@ -163,6 +165,7 @@
                     new IconProvider(context).getIcon(mActivityInfo), appIconSizePx);
             final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
             mPipContentOverlay.attach(tx, mLeash);
+            Log.d(TAG, getContentOverlay() + " is created: " + reasonForCreateOverlay);
         } else {
             mSourceRectHint.set(sourceRectHint);
             mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
@@ -174,19 +177,19 @@
         addAnimatorListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
-                InteractionJankMonitorWrapper.begin(view, CUJ_APP_CLOSE_TO_PIP);
+                InteractionJankMonitorWrapper.begin(view, Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
                 super.onAnimationStart(animation);
             }
 
             @Override
             public void onAnimationCancel(Animator animation) {
                 super.onAnimationCancel(animation);
-                InteractionJankMonitorWrapper.cancel(CUJ_APP_CLOSE_TO_PIP);
+                InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
             }
 
             @Override
             public void onAnimationSuccess(Animator animator) {
-                InteractionJankMonitorWrapper.end(CUJ_APP_CLOSE_TO_PIP);
+                InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_PIP);
             }
 
             @Override
@@ -265,6 +268,10 @@
         return mDestinationBounds;
     }
 
+    public Rect getAppBounds() {
+        return mAppBounds;
+    }
+
     @Nullable
     public SurfaceControl getContentOverlay() {
         return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
index 348e4dc..9268511 100644
--- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.ArrayMap;
+import android.view.DisplayCutout;
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.WindowMetrics;
@@ -74,4 +75,10 @@
         }
         return result;
     }
+
+    @Override
+    protected DisplayCutout rotateCutout(DisplayCutout original, int startWidth, int startHeight,
+            int fromRotation, int toRotation) {
+        return original.getRotated(startWidth, startHeight, fromRotation, toRotation);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
index ddc796f..9a01042 100644
--- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java
+++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java
@@ -108,6 +108,15 @@
         return mBinder == null ? null : mBinder.getTaskbarManager();
     }
 
+    /**
+     * Sets flag whether a predictive back-to-home animation is in progress
+     */
+    public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
+        if (mBinder != null) {
+            mBinder.setPredictiveBackToHomeInProgress(isInProgress);
+        }
+    }
+
     @Nullable
     public OverviewCommandHelper getOverviewCommandHelper() {
         return mBinder == null ? null : mBinder.getOverviewCommandHelper();
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index cdadd71..e80d2a6 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -22,10 +22,12 @@
 import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
 import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
 
+import android.content.Context;
+
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.BaseActivity;
 import com.android.quickstep.RecentsModel;
+import com.android.quickstep.views.RecentsViewContainer;
 
 /**
  * This class tracks the failure of a task launch through the TaskView.launchTask() call, in an
@@ -38,27 +40,33 @@
  */
 public class TaskRemovedDuringLaunchListener {
 
-    private BaseActivity mActivity;
+    private RecentsViewContainer mContainer;
     private int mLaunchedTaskId = INVALID_TASK_ID;
     private Runnable mTaskLaunchFailedCallback = null;
 
     private final Runnable mUnregisterCallback = this::unregister;
     private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
 
+    private final Context mContext;
+
+    public TaskRemovedDuringLaunchListener(Context context) {
+        mContext = context;
+    }
+
     /**
      * Registers a failure listener callback if it detects a scenario in which an app launch
      * failed before the transition finished.
      */
-    public void register(BaseActivity activity, int launchedTaskId,
+    public void register(RecentsViewContainer container, int launchedTaskId,
             @NonNull Runnable taskLaunchFailedCallback) {
         // The normal task launch case, Launcher stops and updates its state correctly
-        activity.addEventCallback(EVENT_STOPPED, mUnregisterCallback);
+        container.addEventCallback(EVENT_STOPPED, mUnregisterCallback);
         // The transition hasn't finished but Launcher was resumed, check if the launch failed
-        activity.addEventCallback(EVENT_RESUMED, mResumeCallback);
+        container.addEventCallback(EVENT_RESUMED, mResumeCallback);
         // If we somehow don't get any of the above signals, then just unregister this listener
-        activity.addEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+        container.addEventCallback(EVENT_DESTROYED, mUnregisterCallback);
 
-        mActivity = activity;
+        mContainer = container;
         mLaunchedTaskId = launchedTaskId;
         mTaskLaunchFailedCallback = taskLaunchFailedCallback;
     }
@@ -67,11 +75,11 @@
      * Unregisters the failure listener.
      */
     private void unregister() {
-        mActivity.removeEventCallback(EVENT_STOPPED, mUnregisterCallback);
-        mActivity.removeEventCallback(EVENT_RESUMED, mResumeCallback);
-        mActivity.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+        mContainer.removeEventCallback(EVENT_STOPPED, mUnregisterCallback);
+        mContainer.removeEventCallback(EVENT_RESUMED, mResumeCallback);
+        mContainer.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback);
 
-        mActivity = null;
+        mContainer = null;
         mLaunchedTaskId = INVALID_TASK_ID;
         mTaskLaunchFailedCallback = null;
     }
@@ -88,7 +96,7 @@
         if (mLaunchedTaskId != INVALID_TASK_ID) {
             final int launchedTaskId = mLaunchedTaskId;
             final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
-            RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
+            RecentsModel.INSTANCE.get(mContext).isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
                 if (taskRemoved) {
                     ActiveGestureLog.INSTANCE.addLog(
                             new ActiveGestureLog.CompoundString("Launch failed, task (id=")
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index baaa062..fcb865f 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -38,9 +38,12 @@
 import android.graphics.RectF;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
+import android.view.animation.Interpolator;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatedFloat;
@@ -48,6 +51,7 @@
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
 import com.android.launcher3.util.TraceHelper;
 import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
@@ -67,13 +71,16 @@
     private final float[] mTempPoint = new float[2];
 
     private final Context mContext;
-    private final BaseActivityInterface mSizeStrategy;
+    private final BaseContainerInterface mSizeStrategy;
 
     @NonNull
     private RecentsOrientedState mOrientationState;
     private final boolean mIsRecentsRtl;
 
     private final Rect mTaskRect = new Rect();
+    private final Rect mFullTaskSize = new Rect();
+    private final Rect mCarouselTaskSize = new Rect();
+    private PointF mPivotOverride = null;
     private final PointF mPivot = new PointF();
     private DeviceProfile mDp;
     @StagePosition
@@ -93,6 +100,11 @@
     public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
     public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
 
+    // Carousel properties
+    public final AnimatedFloat carouselScale = new AnimatedFloat();
+    public final AnimatedFloat carouselPrimaryTranslation = new AnimatedFloat();
+    public final AnimatedFloat carouselSecondaryTranslation = new AnimatedFloat();
+
     // RecentsView properties
     public final AnimatedFloat recentsViewScale = new AnimatedFloat();
     public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
@@ -107,11 +119,11 @@
     private Boolean mDrawsBelowRecents = null;
     private boolean mIsGridTask;
     private boolean mIsDesktopTask;
+    private boolean mScaleToCarouselTaskSize = false;
     private int mTaskRectTranslationX;
     private int mTaskRectTranslationY;
-    private int mPivotOffsetX;
 
-    public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
+    public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy) {
         mContext = context;
         mSizeStrategy = sizeStrategy;
 
@@ -122,6 +134,7 @@
         mOrientationStateId = mOrientationState.getStateId();
         Resources resources = context.getResources();
         mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
+        carouselScale.value = 1f;
     }
 
     /**
@@ -131,6 +144,52 @@
         mDp = dp;
         mLayoutValid = false;
         mOrientationState.setDeviceProfile(dp);
+        calculateTaskSize();
+    }
+
+    private void calculateTaskSize() {
+        if (mDp == null) {
+            return;
+        }
+
+        if (mIsGridTask) {
+            mSizeStrategy.calculateGridTaskSize(mContext, mDp, mFullTaskSize,
+                    mOrientationState.getOrientationHandler());
+        } else {
+            mSizeStrategy.calculateTaskSize(mContext, mDp, mFullTaskSize,
+                    mOrientationState.getOrientationHandler());
+        }
+
+        if (enableGridOnlyOverview()) {
+            mSizeStrategy.calculateCarouselTaskSize(mContext, mDp, mCarouselTaskSize,
+                    mOrientationState.getOrientationHandler());
+        }
+
+        if (mSplitBounds != null) {
+            // The task rect changes according to the staged split task sizes, but recents
+            // fullscreen scale and pivot remains the same since the task fits into the existing
+            // sized task space bounds
+            mTaskRect.set(mFullTaskSize);
+            mOrientationState.getOrientationHandler()
+                    .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
+            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+        } else if (mIsDesktopTask) {
+            // For desktop, tasks can take up only part of the screen size.
+            // Full task size represents the whole screen size, but scaled down to fit in recents.
+            // Task rect will represent the scaled down thumbnail position and is placed inside
+            // full task size as it is on the home screen.
+            PointF fullscreenTaskDimension = new PointF();
+            BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension);
+            // Calculate the scale down factor used in recents
+            float scale = mFullTaskSize.width() / fullscreenTaskDimension.x;
+            mTaskRect.set(mThumbnailPosition);
+            mTaskRect.scale(scale);
+            // Ensure the task rect is inside the full task rect
+            mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
+        } else {
+            mTaskRect.set(mFullTaskSize);
+            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+        }
     }
 
     /**
@@ -148,44 +207,20 @@
         if (mDp == null) {
             return 1;
         }
-
-        if (mIsGridTask) {
-            mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
-                    mOrientationState.getOrientationHandler());
+        // Copy mFullTaskSize instead of updating it directly so it could be reused next time
+        // without recalculating
+        Rect scaleRect = new Rect();
+        if (mScaleToCarouselTaskSize) {
+            scaleRect.set(mCarouselTaskSize);
         } else {
-            mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
-                    mOrientationState.getOrientationHandler());
+            scaleRect.set(mFullTaskSize);
         }
-
-        Rect fullTaskSize;
-        if (mSplitBounds != null) {
-            // The task rect changes according to the staged split task sizes, but recents
-            // fullscreen scale and pivot remains the same since the task fits into the existing
-            // sized task space bounds
-            fullTaskSize = new Rect(mTaskRect);
-            mOrientationState.getOrientationHandler()
-                    .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
-        } else if (mIsDesktopTask) {
-            // For desktop, tasks can take up only part of the screen size.
-            // Full task size represents the whole screen size, but scaled down to fit in recents.
-            // Task rect will represent the scaled down thumbnail position and is placed inside
-            // full task size as it is on the home screen.
-            fullTaskSize = new Rect(mTaskRect);
-            PointF fullscreenTaskDimension = new PointF();
-            BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension);
-            // Calculate the scale down factor used in recents
-            float scale = fullTaskSize.width() / fullscreenTaskDimension.x;
-            mTaskRect.set(mThumbnailPosition);
-            mTaskRect.scale(scale);
-            // Ensure the task rect is inside the full task rect
-            mTaskRect.offset(fullTaskSize.left, fullTaskSize.top);
-        } else {
-            fullTaskSize = new Rect(mTaskRect);
-            mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+        scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+        float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
+        if (mPivotOverride != null) {
+            mPivot.set(mPivotOverride);
         }
-        fullTaskSize.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
-        return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot);
+        return scale;
     }
 
     /**
@@ -209,13 +244,13 @@
         mSplitBounds = splitInfo;
         if (mSplitBounds == null) {
             mStagePosition = STAGE_POSITION_UNDEFINED;
-            return;
+        } else {
+            mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds)
+                    ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
+            mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
+                    mStagePosition);
         }
-        mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds) ?
-                STAGE_POSITION_TOP_OR_LEFT :
-                STAGE_POSITION_BOTTOM_OR_RIGHT;
-        mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
-                mStagePosition);
+        calculateTaskSize();
     }
 
     /**
@@ -261,19 +296,71 @@
     public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) {
         mTaskRectTranslationX = taskRectTranslationX;
         mTaskRectTranslationY = taskRectTranslationY;
+        // Re-calculate task size after changing translation
+        calculateTaskSize();
     }
 
     /**
      * Adds animation for all the components corresponding to transition from an app to overview.
      */
-    public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
+    public void addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator) {
         pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
-        if (enableGridOnlyOverview() && mDp.isTablet) {
-            int translationXToMiddle = mDp.widthPx / 2 - mTaskRect.centerX();
-            taskPrimaryTranslation.value = translationXToMiddle;
-            mPivotOffsetX = translationXToMiddle;
+        float fullScreenScale;
+        if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
+            // Move pivot to top right edge of the screen, to avoid task scaling down in opposite
+            // direction of app window movement, otherwise the animation will wiggle left and right.
+            // Also translate the app window to top right edge of the screen to simplify
+            // calculations.
+            taskPrimaryTranslation.value = mIsRecentsRtl
+                    ? mDp.widthPx - mFullTaskSize.right
+                    : -mFullTaskSize.left;
+            taskSecondaryTranslation.value = -mFullTaskSize.top;
+            mPivotOverride = new PointF(mIsRecentsRtl ? mDp.widthPx : 0, 0);
+
+            // Scale down to the carousel and use the carousel Rect to calculate fullScreenScale.
+            mScaleToCarouselTaskSize = true;
+            carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
+            fullScreenScale = getFullScreenScale();
+
+            float carouselPrimaryTranslationTarget = mIsRecentsRtl
+                    ? mCarouselTaskSize.right - mDp.widthPx
+                    : mCarouselTaskSize.left;
+            float carouselSecondaryTranslationTarget = mCarouselTaskSize.top;
+
+            // Expected carousel position's center is in the middle, and invariant of
+            // recentsViewScale.
+            float exceptedCarouselCenterX = mCarouselTaskSize.centerX();
+            // Animating carousel translations linearly will result in a curved path, therefore
+            // we'll need to calculate the expected translation at each recentsView scale. Luckily
+            // primary and secondary follow the same translation, and primary is used here due to
+            // it being simpler.
+            Interpolator carouselTranslationInterpolator = t -> {
+                // recentsViewScale is calculated rather than using recentsViewScale.value, so that
+                // this interpolator works independently even if recentsViewScale don't animate.
+                float recentsViewScale =
+                        Utilities.mapToRange(t, 0, 1, fullScreenScale, 1, Interpolators.LINEAR);
+                // Without the translation, the app window will animate from fullscreen into top
+                // right corner.
+                float expectedTaskCenterX = mIsRecentsRtl
+                        ? mDp.widthPx - mCarouselTaskSize.width() * recentsViewScale / 2f
+                        : mCarouselTaskSize.width() * recentsViewScale / 2f;
+                // Calculate the expected translation, then work back the animatedFraction that
+                // results in this value.
+                float carouselPrimaryTranslation =
+                        (exceptedCarouselCenterX - expectedTaskCenterX) / recentsViewScale;
+                return carouselPrimaryTranslation / carouselPrimaryTranslationTarget;
+            };
+
+            // Use addAnimatedFloat so this animation can later be canceled and animate to a
+            // different value in RecentsView.onPrepareGestureEndAnimation.
+            pa.addAnimatedFloat(carouselPrimaryTranslation, 0, carouselPrimaryTranslationTarget,
+                    carouselTranslationInterpolator);
+            pa.addAnimatedFloat(carouselSecondaryTranslation, 0, carouselSecondaryTranslationTarget,
+                    carouselTranslationInterpolator);
+        } else {
+            fullScreenScale = getFullScreenScale();
         }
-        pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, interpolator);
+        pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, fullScreenScale, 1, interpolator);
     }
 
     /**
@@ -324,8 +411,8 @@
     public void applyWindowToHomeRotation(Matrix matrix) {
         matrix.postTranslate(mDp.windowX, mDp.windowY);
         postDisplayRotation(deltaRotation(
-                mOrientationState.getRecentsActivityRotation(),
-                mOrientationState.getDisplayRotation()),
+                        mOrientationState.getRecentsActivityRotation(),
+                        mOrientationState.getDisplayRotation()),
                 mDp.widthPx, mDp.heightPx, matrix);
     }
 
@@ -333,6 +420,14 @@
      * Applies the target to the previously set parameters
      */
     public void apply(TransformParams params) {
+        apply(params, null);
+    }
+
+    /**
+     * Applies the target to the previously set parameters, optionally with an overridden
+     * surface transaction
+     */
+    public void apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction) {
         if (mDp == null || mThumbnailPosition.isEmpty()) {
             return;
         }
@@ -362,7 +457,7 @@
 
         float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1);
         mCurrentFullscreenParams.setProgress(fullScreenProgress, recentsViewScale.value,
-                /* taskViewScale= */1f);
+                carouselScale.value);
 
         // Apply thumbnail matrix
         float taskWidth = mTaskRect.width();
@@ -376,6 +471,13 @@
                 taskPrimaryTranslation.value);
         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
                 taskSecondaryTranslation.value);
+
+        mMatrix.postScale(carouselScale.value, carouselScale.value, mPivot.x, mPivot.y);
+        mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
+                carouselPrimaryTranslation.value);
+        mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
+                carouselSecondaryTranslation.value);
+
         mOrientationState.getOrientationHandler().setPrimary(
                 mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
 
@@ -393,21 +495,25 @@
         mTempRectF.roundOut(mTmpCropRect);
 
         params.setProgress(1f - fullScreenProgress);
-        params.applySurfaceParams(params.createSurfaceParams(this));
+        params.applySurfaceParams(surfaceTransaction == null
+                ? params.createSurfaceParams(this) : surfaceTransaction);
 
         if (!DEBUG) {
             return;
         }
         Log.d(TAG, "progress: " + fullScreenProgress
+                + " carouselScale: " + carouselScale.value
                 + " recentsViewScale: " + recentsViewScale.value
                 + " crop: " + mTmpCropRect
                 + " radius: " + getCurrentCornerRadius()
                 + " taskW: " + taskWidth + " H: " + taskHeight
                 + " taskRect: " + mTaskRect
                 + " taskPrimaryT: " + taskPrimaryTranslation.value
+                + " taskSecondaryT: " + taskSecondaryTranslation.value
+                + " carouselPrimaryT: " + carouselPrimaryTranslation.value
+                + " carouselSecondaryT: " + carouselSecondaryTranslation.value
                 + " recentsPrimaryT: " + recentsViewPrimaryTranslation.value
                 + " recentsSecondaryT: " + recentsViewSecondaryTranslation.value
-                + " taskSecondaryT: " + taskSecondaryTranslation.value
                 + " recentsScroll: " + recentsViewScroll.value
                 + " pivot: " + mPivot
         );
diff --git a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index 7bbde30..c63a58e 100644
--- a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -28,6 +28,8 @@
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 
@@ -41,21 +43,20 @@
     private final float mMinFlingVelocity;
     private final boolean mDisableHorizontalSwipe;
     private final NavBarPosition mNavBarPosition;
-    private final Runnable mOnInterceptTouch;
+
+    @NonNull
     private final OnSwipeUpListener mOnSwipeUp;
 
     private boolean mInterceptedTouch;
     private VelocityTracker mVelocityTracker;
 
     public TriggerSwipeUpTouchTracker(Context context, boolean disableHorizontalSwipe,
-            NavBarPosition navBarPosition, Runnable onInterceptTouch,
-            OnSwipeUpListener onSwipeUp) {
+            NavBarPosition navBarPosition, @NonNull OnSwipeUpListener onSwipeUp) {
         mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
         mMinFlingVelocity = context.getResources().getDimension(
                 R.dimen.quickstep_fling_threshold_speed);
         mNavBarPosition = navBarPosition;
         mDisableHorizontalSwipe = disableHorizontalSwipe;
-        mOnInterceptTouch = onInterceptTouch;
         mOnSwipeUp = onSwipeUp;
 
         init();
@@ -103,10 +104,7 @@
                         }
 
                         mInterceptedTouch = true;
-
-                        if (mOnInterceptTouch != null) {
-                            mOnInterceptTouch.run();
-                        }
+                        mOnSwipeUp.onSwipeUpTouchIntercepted();
                     }
                 }
                 break;
@@ -124,7 +122,8 @@
         }
     }
 
-    private void endTouchTracking() {
+    /** Finishes the tracking. All events after this call are ignored */
+    public void endTouchTracking() {
         if (mVelocityTracker != null) {
             mVelocityTracker.recycle();
             mVelocityTracker = null;
@@ -151,12 +150,10 @@
             isSwipeUp = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop;
         }
 
-        if (mOnSwipeUp != null) {
-            if (isSwipeUp) {
-                mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY));
-            } else {
-                mOnSwipeUp.onSwipeUpCancelled();
-            }
+        if (isSwipeUp) {
+            mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY));
+        } else {
+            mOnSwipeUp.onSwipeUpCancelled();
         }
     }
 
@@ -172,6 +169,9 @@
         void onSwipeUp(boolean wasFling, PointF finalVelocity);
 
         /** Called on touch up if a swipe up was not detected. */
-        void onSwipeUpCancelled();
+        default void onSwipeUpCancelled() { }
+
+        /** Called when the touch for swipe up is intercepted. */
+        default void onSwipeUpTouchIntercepted() { }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
index c8141b4..4aea1b8 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterHotseatAnimator.java
@@ -20,7 +20,7 @@
 import android.view.WindowManager;
 
 import com.android.launcher3.Hotseat;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.systemui.unfold.updates.RotationChangeProvider;
 
 /**
@@ -28,10 +28,10 @@
  */
 public class UnfoldMoveFromCenterHotseatAnimator extends BaseUnfoldMoveFromCenterAnimator {
 
-    private final Launcher mLauncher;
+    private final QuickstepLauncher mLauncher;
 
-    public UnfoldMoveFromCenterHotseatAnimator(Launcher launcher, WindowManager windowManager,
-            RotationChangeProvider rotationChangeProvider) {
+    public UnfoldMoveFromCenterHotseatAnimator(QuickstepLauncher launcher,
+            WindowManager windowManager, RotationChangeProvider rotationChangeProvider) {
         super(windowManager, rotationChangeProvider);
         mLauncher = launcher;
     }
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index c05b38f..0ec3ae0 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -19,9 +19,9 @@
 import android.view.WindowManager;
 
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.systemui.unfold.updates.RotationChangeProvider;
 
 /**
@@ -29,10 +29,10 @@
  */
 public class UnfoldMoveFromCenterWorkspaceAnimator extends BaseUnfoldMoveFromCenterAnimator {
 
-    private final Launcher mLauncher;
+    private final QuickstepLauncher mLauncher;
 
-    public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager,
-            RotationChangeProvider rotationChangeProvider) {
+    public UnfoldMoveFromCenterWorkspaceAnimator(QuickstepLauncher launcher,
+            WindowManager windowManager, RotationChangeProvider rotationChangeProvider) {
         super(windowManager, rotationChangeProvider);
         mLauncher = launcher;
     }
diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherJankMonitorTransitionProgressListener.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherJankMonitorTransitionProgressListener.kt
index 4f89c7e..b4ca35e 100644
--- a/quickstep/src/com/android/quickstep/util/unfold/LauncherJankMonitorTransitionProgressListener.kt
+++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherJankMonitorTransitionProgressListener.kt
@@ -16,6 +16,7 @@
 package com.android.quickstep.util.unfold
 
 import android.view.View
+import com.android.internal.jank.Cuj
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
 import java.util.function.Supplier
@@ -28,11 +29,11 @@
     override fun onTransitionStarted() {
         InteractionJankMonitorWrapper.begin(
             attachedViewProvider.get(),
-            InteractionJankMonitorWrapper.CUJ_LAUNCHER_UNFOLD_ANIM
+            Cuj.CUJ_LAUNCHER_UNFOLD_ANIM
         )
     }
 
     override fun onTransitionFinished() {
-        InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_LAUNCHER_UNFOLD_ANIM)
+        InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_UNFOLD_ANIM)
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
new file mode 100644
index 0000000..09563f5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util.unfold
+
+import android.app.Activity
+import android.os.Trace
+import android.view.Surface
+import com.android.launcher3.Alarm
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+
+/** Controls animations that are happening during unfolding foldable devices */
+class LauncherUnfoldTransitionController(
+    private val launcher: QuickstepLauncher,
+    private val progressProvider: ProxyUnfoldTransitionProvider
+) : OnDeviceProfileChangeListener, ActivityLifecycleCallbacksAdapter, TransitionProgressListener {
+
+    private var isTablet: Boolean? = null
+    private var hasUnfoldTransitionStarted = false
+    private val timeoutAlarm =
+        Alarm().apply {
+            setOnAlarmListener {
+                onTransitionFinished()
+                Trace.endAsyncSection("$TAG#startedPreemptively", 0)
+            }
+        }
+
+    init {
+        launcher.addOnDeviceProfileChangeListener(this)
+        launcher.registerActivityLifecycleCallbacks(this)
+    }
+
+    override fun onActivityPaused(activity: Activity) {
+        progressProvider.removeCallback(this)
+    }
+
+    override fun onActivityResumed(activity: Activity) {
+        progressProvider.addCallback(this)
+    }
+
+    override fun onDeviceProfileChanged(dp: DeviceProfile) {
+        if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) {
+            return
+        }
+
+        if (isTablet != null && dp.isTablet != isTablet) {
+            // We should preemptively start the animation only if:
+            // - We changed to the unfolded screen
+            // - SystemUI IPC connection is alive, so we won't end up in a situation that we won't
+            //   receive transition progress events from SystemUI later because there was no
+            //   IPC connection established (e.g. because of SystemUI crash)
+            // - SystemUI has not already sent unfold animation progress events. This might happen
+            //   if Launcher was not open during unfold, in this case we receive the configuration
+            //   change only after we went back to home screen and we don't want to start the
+            //   animation in this case.
+            if (dp.isTablet && progressProvider.isActive && !hasUnfoldTransitionStarted) {
+                // Preemptively start the unfold animation to make sure that we have drawn
+                // the first frame of the animation before the screen gets unblocked
+                onTransitionStarted()
+                Trace.beginAsyncSection("$TAG#startedPreemptively", 0)
+                timeoutAlarm.setAlarm(PREEMPTIVE_UNFOLD_TIMEOUT_MS)
+            }
+            if (!dp.isTablet) {
+                // Reset unfold transition status when folded
+                hasUnfoldTransitionStarted = false
+            }
+        }
+
+        isTablet = dp.isTablet
+    }
+
+    override fun onTransitionStarted() {
+        hasUnfoldTransitionStarted = true
+        launcher.animationCoordinator.setAnimation(
+            provider = this,
+            factory = this::onPrepareUnfoldAnimation,
+            duration =
+                1000L // The expected duration for the animation. Then only comes to play if we have
+            // to run the animation ourselves in case sysui misses the end signal
+        )
+        timeoutAlarm.cancelAlarm()
+    }
+
+    override fun onTransitionProgress(progress: Float) {
+        hasUnfoldTransitionStarted = true
+        launcher.animationCoordinator.getPlaybackController(this)?.setPlayFraction(progress)
+    }
+
+    override fun onTransitionFinished() {
+        // Run the animation to end the animation in case it is not already at end progress. It
+        // will scale the duration to the remaining progress
+        launcher.animationCoordinator.getPlaybackController(this)?.start()
+        timeoutAlarm.cancelAlarm()
+    }
+
+    private fun onPrepareUnfoldAnimation(anim: PendingAnimation) {
+        val dp = launcher.deviceProfile
+        val rotation = dp.displayInfo.rotation
+        val isVertical = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
+        UnfoldAnimationBuilder.buildUnfoldAnimation(
+            launcher,
+            isVertical,
+            dp.displayInfo.currentSize,
+            anim
+        )
+    }
+
+    companion object {
+        private const val TAG = "LauncherUnfoldTransitionController"
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/unfold/ProxyUnfoldTransitionProvider.kt b/quickstep/src/com/android/quickstep/util/unfold/ProxyUnfoldTransitionProvider.kt
new file mode 100644
index 0000000..83c7f72
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/unfold/ProxyUnfoldTransitionProvider.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util.unfold
+
+import androidx.annotation.AnyThread
+import androidx.annotation.FloatRange
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
+import com.android.systemui.unfold.progress.IUnfoldTransitionListener
+import com.android.systemui.unfold.progress.UnfoldRemoteFilter
+
+/** Receives unfold events from remote senders (System UI). */
+class ProxyUnfoldTransitionProvider :
+    UnfoldTransitionProgressProvider, IUnfoldTransitionListener.Stub() {
+
+    private val listeners: MutableSet<TransitionProgressListener> = mutableSetOf()
+    private val delegate = UnfoldRemoteFilter(ProcessedProgressListener())
+
+    private var transitionStarted = false
+    var isActive = false
+        set(value) {
+            field = value
+            if (!value) {
+                // Finish any active transition
+                onTransitionFinished()
+            }
+        }
+
+    @AnyThread
+    override fun onTransitionStarted() {
+        MAIN_EXECUTOR.execute(delegate::onTransitionStarted)
+    }
+
+    @AnyThread
+    override fun onTransitionProgress(progress: Float) {
+        MAIN_EXECUTOR.execute { delegate.onTransitionProgress(progress) }
+    }
+
+    @AnyThread
+    override fun onTransitionFinished() {
+        MAIN_EXECUTOR.execute(delegate::onTransitionFinished)
+    }
+
+    override fun addCallback(listener: TransitionProgressListener) {
+        listeners += listener
+        if (transitionStarted) {
+            // Update the listener in case there was is an active transition
+            listener.onTransitionStarted()
+        }
+    }
+
+    override fun removeCallback(listener: TransitionProgressListener) {
+        listeners -= listener
+        if (transitionStarted) {
+            // Finish the transition if it was already running
+            listener.onTransitionFinished()
+        }
+    }
+
+    override fun destroy() {
+        listeners.clear()
+    }
+
+    private inner class ProcessedProgressListener : TransitionProgressListener {
+        override fun onTransitionStarted() {
+            if (!transitionStarted) {
+                transitionStarted = true
+                listeners.forEach(TransitionProgressListener::onTransitionStarted)
+            }
+        }
+
+        override fun onTransitionProgress(@FloatRange(from = 0.0, to = 1.0) progress: Float) {
+            listeners.forEach { it.onTransitionProgress(progress) }
+        }
+
+        override fun onTransitionFinished() {
+            if (transitionStarted) {
+                transitionStarted = false
+                listeners.forEach(TransitionProgressListener::onTransitionFinished)
+            }
+        }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt b/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt
new file mode 100644
index 0000000..2f90ee7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/unfold/UnfoldAnimationBuilder.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util.unfold
+
+import android.graphics.Point
+import android.view.ViewGroup
+import com.android.app.animation.Interpolators.LINEAR
+import com.android.app.animation.Interpolators.clampToProgress
+import com.android.launcher3.CellLayout
+import com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_UNFOLD_ANIMATION
+import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X
+import com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y
+import com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.Workspace
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.launcher3.util.HorizontalInsettableView
+
+private typealias ViewGroupAction = (ViewGroup, Boolean) -> Unit
+
+object UnfoldAnimationBuilder {
+
+    private val CLIP_CHILDREN: ViewGroupAction = ViewGroup::setClipChildren
+    private val CLIP_TO_PADDING: ViewGroupAction = ViewGroup::setClipToPadding
+
+    data class RestoreInfo(val action: ViewGroupAction, var target: ViewGroup, var value: Boolean)
+
+    // Percentage of the width of the quick search bar that will be reduced
+    // from the both sides of the bar when progress is 0
+    private const val MAX_WIDTH_INSET_FRACTION = 0.04f
+
+    // Scale factor for the whole workspace and hotseat
+    private const val SCALE_LAUNCHER_FROM = 0.92f
+
+    // Translation factor for all the items on the homescreen
+    private const val TRANSLATION_PERCENTAGE = 0.08f
+
+    private fun setClipChildren(
+        target: ViewGroup,
+        value: Boolean,
+        restoreList: MutableList<RestoreInfo>
+    ) {
+        val originalValue = target.clipChildren
+        if (originalValue != value) {
+            target.clipChildren = value
+            restoreList.add(RestoreInfo(CLIP_CHILDREN, target, originalValue))
+        }
+    }
+
+    private fun setClipToPadding(
+        target: ViewGroup,
+        value: Boolean,
+        restoreList: MutableList<RestoreInfo>
+    ) {
+        val originalValue = target.clipToPadding
+        if (originalValue != value) {
+            target.clipToPadding = value
+            restoreList.add(RestoreInfo(CLIP_TO_PADDING, target, originalValue))
+        }
+    }
+
+    private fun addChildrenAnimation(
+        itemsContainer: ViewGroup,
+        isVerticalFold: Boolean,
+        screenSize: Point,
+        anim: PendingAnimation
+    ) {
+        val tempLocation = IntArray(2)
+        for (i in 0 until itemsContainer.childCount) {
+            val child = itemsContainer.getChildAt(i)
+
+            child.getLocationOnScreen(tempLocation)
+            if (isVerticalFold) {
+                val viewCenterX = tempLocation[0] + child.width / 2
+                val distanceFromScreenCenterToViewCenter = screenSize.x / 2 - viewCenterX
+                anim.addFloat(
+                    child,
+                    VIEW_TRANSLATE_X,
+                    distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE,
+                    0f,
+                    LINEAR
+                )
+            } else {
+                val viewCenterY = tempLocation[1] + child.height / 2
+                val distanceFromScreenCenterToViewCenter = screenSize.y / 2 - viewCenterY
+                anim.addFloat(
+                    child,
+                    VIEW_TRANSLATE_Y,
+                    distanceFromScreenCenterToViewCenter * TRANSLATION_PERCENTAGE,
+                    0f,
+                    LINEAR
+                )
+            }
+        }
+    }
+
+    /**
+     * Builds an animation for the unfold experience and adds it to the provided PendingAnimation
+     */
+    fun buildUnfoldAnimation(
+        launcher: QuickstepLauncher,
+        isVerticalFold: Boolean,
+        screenSize: Point,
+        anim: PendingAnimation
+    ) {
+        val restoreList = ArrayList<RestoreInfo>()
+        val registerViews: (CellLayout) -> Unit = { cellLayout ->
+            setClipChildren(cellLayout, false, restoreList)
+            setClipToPadding(cellLayout, false, restoreList)
+            addChildrenAnimation(cellLayout.shortcutsAndWidgets, isVerticalFold, screenSize, anim)
+        }
+
+        val workspace: Workspace<*> = launcher.workspace
+        val hotseat = launcher.hotseat
+
+        // Animation icons from workspace for all orientations
+        workspace.forEachVisiblePage { registerViews(it as CellLayout) }
+        setClipChildren(workspace, false, restoreList)
+        setClipToPadding(workspace, true, restoreList)
+
+        // Workspace scale
+        launcher.workspace.setPivotToScaleWithSelf(launcher.hotseat)
+        val interpolator = clampToProgress(LINEAR, 0f, 1f)
+        anim.addFloat(
+            workspace,
+            WORKSPACE_SCALE_PROPERTY_FACTORY[SCALE_INDEX_UNFOLD_ANIMATION],
+            SCALE_LAUNCHER_FROM,
+            1f,
+            interpolator
+        )
+        anim.addFloat(
+            hotseat,
+            HOTSEAT_SCALE_PROPERTY_FACTORY[SCALE_INDEX_UNFOLD_ANIMATION],
+            SCALE_LAUNCHER_FROM,
+            1f,
+            interpolator
+        )
+
+        if (isVerticalFold) {
+            if (hotseat.qsb is HorizontalInsettableView) {
+                anim.addFloat(
+                    hotseat.qsb as HorizontalInsettableView,
+                    HorizontalInsettableView.HORIZONTAL_INSETS,
+                    MAX_WIDTH_INSET_FRACTION,
+                    0f,
+                    LINEAR
+                )
+            }
+            registerViews(hotseat)
+        }
+        anim.addEndListener { restoreList.forEach { it.action(it.target, it.value) } }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index fdc8f1f..121d8ed 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN;
+import static com.android.quickstep.util.AnimUtils.clampToDuration;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -187,10 +188,14 @@
         intro.setInterpolator(LINEAR);
         intro.setDuration(introDuration);
         intro.addUpdateListener((new MultiValueUpdateListener() {
-            FloatProp mCircleAlpha = new FloatProp(0, 255, 0, firstPart, LINEAR);
-            FloatProp mCircleScale = new FloatProp(2f, 1f, 0, firstPart, OVERSHOOT_1_7);
-            FloatProp mDeltaY = new FloatProp(0, transY, firstPart, secondPart, FAST_OUT_SLOW_IN);
-            FloatProp mGradientAlpha = new FloatProp(0, 255, firstPart, secondPart * 0.3f, LINEAR);
+            FloatProp mCircleAlpha = new FloatProp(0, 255,
+                    clampToDuration(LINEAR, 0, firstPart, introDuration));
+            FloatProp mCircleScale = new FloatProp(2f, 1f,
+                    clampToDuration(OVERSHOOT_1_7, 0, firstPart, introDuration));
+            FloatProp mDeltaY = new FloatProp(0, transY,
+                    clampToDuration(FAST_OUT_SLOW_IN, firstPart, secondPart, introDuration));
+            FloatProp mGradientAlpha = new FloatProp(0, 255,
+                    clampToDuration(LINEAR, firstPart, secondPart * 0.3f, introDuration));
 
             @Override
             public void onUpdate(float progress, boolean initOnly) {
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index fba847f..b8afd9d 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -17,15 +17,28 @@
 package com.android.quickstep.views;
 
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.widget.Button;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
+import com.android.launcher3.R;
 import com.android.launcher3.statemanager.StatefulActivity;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.BorderAnimator;
+
+import kotlin.Unit;
 
 public class ClearAllButton extends Button {
 
@@ -55,7 +68,7 @@
                 }
             };
 
-    private final StatefulActivity mActivity;
+    private final RecentsViewContainer mContainer;
     private float mScrollAlpha = 1;
     private float mContentAlpha = 1;
     private float mVisibilityAlpha = 1;
@@ -71,17 +84,78 @@
     private float mScrollOffsetPrimary;
 
     private int mSidePadding;
+    private int mOutlinePadding;
+    private boolean mBorderEnabled;
+    @Nullable
+    private final BorderAnimator mFocusBorderAnimator;
 
     public ClearAllButton(Context context, AttributeSet attrs) {
         super(context, attrs);
         mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        mActivity = StatefulActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
+
+        if (Flags.enableFocusOutline()) {
+            TypedArray styledAttrs = context.obtainStyledAttributes(attrs,
+                    R.styleable.ClearAllButton);
+            Resources resources = getResources();
+            mOutlinePadding = resources.getDimensionPixelSize(
+                    R.dimen.recents_clear_all_outline_padding);
+            mFocusBorderAnimator =
+                    BorderAnimator.createSimpleBorderAnimator(
+                            /* borderRadiusPx= */ resources.getDimensionPixelSize(
+                                    R.dimen.recents_clear_all_outline_radius),
+                            /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+                                    R.dimen.keyboard_quick_switch_border_width),
+                            /* boundsBuilder= */ this::updateBorderBounds,
+                            /* targetView= */ this,
+                            /* borderColor= */ styledAttrs.getColor(
+                                    R.styleable.ClearAllButton_focusBorderColor,
+                                    DEFAULT_BORDER_COLOR));
+            styledAttrs.recycle();
+        } else {
+            mFocusBorderAnimator = null;
+        }
+    }
+
+    private Unit updateBorderBounds(@NonNull Rect bounds) {
+        bounds.set(0, 0, getWidth(), getHeight());
+        // Make the value negative to form a padding between button and outline
+        bounds.inset(-mOutlinePadding, -mOutlinePadding);
+        return Unit.INSTANCE;
+    }
+
+    @Override
+    public void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (mFocusBorderAnimator != null && mBorderEnabled) {
+            mFocusBorderAnimator.setBorderVisibility(gainFocus, /* animated= */ true);
+        }
+    }
+
+    /**
+     * Enable or disable showing border on focus change
+     */
+    public void setBorderEnabled(boolean enabled) {
+        mBorderEnabled = enabled;
+        if (mFocusBorderAnimator != null) {
+            mFocusBorderAnimator.setBorderVisibility(/* visible= */
+                    enabled && isFocused(), /* animated= */true);
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        if (mFocusBorderAnimator != null) {
+            mFocusBorderAnimator.drawBorder(canvas);
+        }
+        super.draw(canvas);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                getRecentsView().getPagedOrientationHandler();
         mSidePadding = orientationHandler.getClearAllSidePadding(getRecentsView(), mIsRtl);
     }
 
@@ -131,7 +205,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
         if (orientationSize == 0) {
             return;
@@ -219,7 +294,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         orientationHandler.getPrimaryViewTranslate().set(this,
                 orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
                         + mNormalTranslationPrimary + getFullscreenTrans(
@@ -232,7 +308,8 @@
             return;
         }
 
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         orientationHandler.getSecondaryViewTranslate().set(this,
                 orientationHandler.getSecondaryValue(0f, getOriginalTranslationY()));
     }
@@ -249,7 +326,7 @@
      * Get the Y translation that is set in the original layout position, before scrolling.
      */
     private float getOriginalTranslationY() {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         if (deviceProfile.isTablet) {
             if (enableGridOnlyOverview()) {
                 return (getRecentsView().getLastComputedTaskSize().height()
diff --git a/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java b/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java
index a5be142..6a9a268 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopAppSelectView.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 
 /**
  * Floating view show on launcher home screen that notifies the user that an app will be launched to
@@ -47,7 +48,7 @@
     private static final int SHOW_CONTENT_ALPHA_DURATION = 83;
     private static final int HIDE_DURATION = 83;
 
-    private final Launcher mLauncher;
+    private final RecentsViewContainer mContainer;
 
     private View mText;
     private View mCloseButton;
@@ -71,7 +72,7 @@
     public DesktopAppSelectView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mLauncher = Launcher.getLauncher(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
     }
 
     /**
@@ -104,7 +105,7 @@
     }
 
     private void show() {
-        mLauncher.getDragLayer().addView(this);
+        mContainer.getDragLayer().addView(this);
 
         // Set up initial values
         getBackground().setAlpha(0);
@@ -163,7 +164,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                mLauncher.getDragLayer().removeView(DesktopAppSelectView.this);
+                mContainer.getDragLayer().removeView(DesktopAppSelectView.this);
                 mHideAnimation = null;
             }
         });
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index a10d2ed..78b1763 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -17,6 +17,7 @@
 package com.android.quickstep.views;
 
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 
 import android.content.Context;
@@ -27,7 +28,6 @@
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.ShapeDrawable;
 import android.graphics.drawable.shapes.RoundRectShape;
-import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -43,15 +43,16 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
 import com.android.launcher3.icons.IconProvider;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.RunnableList;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.system.QuickStepContract;
-import com.android.wm.shell.Flags;
+
+import kotlin.Unit;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -60,19 +61,12 @@
 import java.util.List;
 import java.util.function.Consumer;
 
-import kotlin.Unit;
-
 /**
  * TaskView that contains all tasks that are part of the desktop.
  */
 // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
 public class DesktopTaskView extends TaskView {
 
-    private static final boolean DESKTOP_MODE_SUPPORTED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode_2", false);
-
-    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
-
     private static final String TAG = DesktopTaskView.class.getSimpleName();
 
     private static final boolean DEBUG = false;
@@ -91,16 +85,7 @@
 
     private View mBackgroundView;
 
-    /** Check whether desktop windowing is enabled */
-    public static boolean isDesktopModeSupported() {
-        // Check for aconfig flag first
-        if (ENABLE_DESKTOP_WINDOWING) {
-            return true;
-        }
-        // Fall back to sysprop flag
-        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
-        return DESKTOP_MODE_SUPPORTED;
-    }
+    private int mChildCountAtInflation;
 
     public DesktopTaskView(Context context) {
         this(context, null);
@@ -133,7 +118,7 @@
         mBackgroundView = findViewById(R.id.background);
 
         int topMarginPx =
-                mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+                mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
         FrameLayout.LayoutParams params = (LayoutParams) mBackgroundView.getLayoutParams();
         params.topMargin = topMarginPx;
         mBackgroundView.setLayoutParams(params);
@@ -151,6 +136,8 @@
         Drawable iconBackground = getResources().getDrawable(R.drawable.bg_circle,
                 getContext().getTheme());
         mIconView.setDrawable(new LayerDrawable(new Drawable[]{iconBackground, icon}));
+
+        mChildCountAtInflation = getChildCount();
     }
 
     @Override
@@ -196,7 +183,9 @@
             for (int i = 0; i < diff; i++) {
                 TaskThumbnailView snapshotView = new TaskThumbnailView(getContext());
                 mSnapshotViews.add(snapshotView);
-                addView(snapshotView, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+                // Add snapshots from to position after the initial child views.
+                addView(snapshotView, mChildCountAtInflation,
+                        new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
             }
         }
 
@@ -314,7 +303,7 @@
 
     @Override
     protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
 
         LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
@@ -431,7 +420,7 @@
 
         setMeasuredDimension(containerWidth, containerHeight);
 
-        int thumbnailTopMarginPx = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+        int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
         containerHeight -= thumbnailTopMarginPx;
 
         int thumbnails = mSnapshotViewMap.size();
@@ -439,8 +428,8 @@
             return;
         }
 
-        int windowWidth = mActivity.getDeviceProfile().widthPx;
-        int windowHeight = mActivity.getDeviceProfile().heightPx;
+        int windowWidth = mContainer.getDeviceProfile().widthPx;
+        int windowHeight = mContainer.getDeviceProfile().heightPx;
 
         float scaleWidth = containerWidth / (float) windowWidth;
         float scaleHeight = containerHeight / (float) windowHeight;
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 57b265b..82ba30b 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -19,9 +19,8 @@
 import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
 
 import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
+import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
 
-import android.annotation.TargetApi;
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
 import android.content.Intent;
@@ -33,7 +32,6 @@
 import android.icu.text.MeasureFormat.FormatWidth;
 import android.icu.util.Measure;
 import android.icu.util.MeasureUnit;
-import android.os.Build;
 import android.os.UserHandle;
 import android.util.Log;
 import android.util.Pair;
@@ -47,13 +45,11 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 
-import com.android.launcher3.BaseActivity;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.lang.annotation.Retention;
@@ -61,7 +57,6 @@
 import java.time.Duration;
 import java.util.Locale;
 
-@TargetApi(Build.VERSION_CODES.Q)
 public final class DigitalWellBeingToast {
 
     private static final float THRESHOLD_LEFT_ICON_ONLY = 0.4f;
@@ -86,7 +81,7 @@
 
     private static final String TAG = DigitalWellBeingToast.class.getSimpleName();
 
-    private final BaseDraggingActivity mActivity;
+    private final RecentsViewContainer mContainer;
     private final TaskView mTaskView;
     private final LauncherApps mLauncherApps;
 
@@ -105,10 +100,10 @@
     private float mSplitOffsetTranslationY;
     private float mSplitOffsetTranslationX;
 
-    public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) {
-        mActivity = activity;
+    public DigitalWellBeingToast(RecentsViewContainer container, TaskView taskView) {
+        mContainer = container;
         mTaskView = taskView;
-        mLauncherApps = activity.getSystemService(LauncherApps.class);
+        mLauncherApps = container.asContext().getSystemService(LauncherApps.class);
     }
 
     private void setNoLimit() {
@@ -123,9 +118,10 @@
         mAppUsageLimitTimeMs = appUsageLimitTimeMs;
         mAppRemainingTimeMs = appRemainingTimeMs;
         mHasLimit = true;
-        TextView toast = mActivity.getViewCache().getView(R.layout.digital_wellbeing_toast,
-                mActivity, mTaskView);
-        toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText()));
+        TextView toast = mContainer.getViewCache().getView(R.layout.digital_wellbeing_toast,
+                mContainer.asContext(), mTaskView);
+        toast.setText(prefixTextWithIcon(mContainer.asContext(), R.drawable.ic_hourglass_top,
+                getText()));
         toast.setOnClickListener(this::openAppUsageSettings);
         replaceBanner(toast);
 
@@ -144,7 +140,7 @@
     public void initialize(Task task) {
         mAppUsageLimitTimeMs = mAppRemainingTimeMs = -1;
         mTask = task;
-        THREAD_POOL_EXECUTOR.execute(() -> {
+        ORDERED_BG_EXECUTOR.execute(() -> {
                     AppUsageLimit usageLimit = null;
                     try {
                         usageLimit = mLauncherApps.getAppUsageLimit(
@@ -173,14 +169,14 @@
     public void setSplitConfiguration(SplitBounds splitBounds) {
         mSplitBounds = splitBounds;
         if (mSplitBounds == null
-                || !mActivity.getDeviceProfile().isTablet
+                || !mContainer.getDeviceProfile().isTablet
                 || mTaskView.isFocusedTask()) {
             mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN;
             return;
         }
 
         // For portrait grid only height of task changes, not width. So we keep the text the same
-        if (!mActivity.getDeviceProfile().isLeftRightSplit) {
+        if (!mContainer.getDeviceProfile().isLeftRightSplit) {
             mSplitBannerConfig = SPLIT_GRID_BANNER_LARGE;
             return;
         }
@@ -229,7 +225,7 @@
 
         // Use a specific string for usage less than one minute but non-zero.
         if (duration.compareTo(Duration.ZERO) > 0) {
-            return mActivity.getString(durationLessThanOneMinuteStringId);
+            return mContainer.asContext().getString(durationLessThanOneMinuteStringId);
         }
 
         // Otherwise, return 0-minute string.
@@ -253,7 +249,7 @@
                 R.string.shorter_duration_less_than_one_minute,
                 false /* forceFormatWidth */);
         if (forContentDesc || mSplitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
-            return mActivity.getString(
+            return mContainer.asContext().getString(
                     R.string.time_left_for_app,
                     readableDuration);
         }
@@ -273,11 +269,12 @@
                         mTask.getTopComponent().getPackageName()).addFlags(
                         Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
         try {
-            final BaseActivity activity = BaseActivity.fromContext(view.getContext());
+            final RecentsViewContainer container =
+                    RecentsViewContainer.containerFromContext(view.getContext());
             final ActivityOptions options = ActivityOptions.makeScaleUpAnimation(
                     view, 0, 0,
                     view.getWidth(), view.getHeight());
-            activity.startActivity(intent, options.toBundle());
+            container.asContext().startActivity(intent, options.toBundle());
 
             // TODO: add WW logging on the app usage settings click.
         } catch (ActivityNotFoundException e) {
@@ -289,7 +286,7 @@
     private String getContentDescriptionForTask(
             Task task, long appUsageLimitTimeMs, long appRemainingTimeMs) {
         return appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0 ?
-                mActivity.getString(
+                mContainer.asContext().getString(
                         R.string.task_contents_description_with_remaining_time,
                         task.titleDescription,
                         getText(appRemainingTimeMs, true /* forContentDesc */)) :
@@ -306,7 +303,7 @@
             mBanner.setOutlineProvider(mOldBannerOutlineProvider);
             mTaskView.removeView(mBanner);
             mBanner.setOnClickListener(null);
-            mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner);
+            mContainer.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner);
         }
     }
 
@@ -321,10 +318,10 @@
     private void setupAndAddBanner() {
         FrameLayout.LayoutParams layoutParams =
                 (FrameLayout.LayoutParams) mBanner.getLayoutParams();
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
                 mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
-        PagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler = mTaskView.getPagedOrientationHandler();
         Pair<Float, Float> translations = orientationHandler
                 .getDwbLayoutTranslations(mTaskView.getMeasuredWidth(),
                         mTaskView.getMeasuredHeight(), mSplitBounds, deviceProfile,
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
index 3a5873b..0d49309 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
@@ -26,7 +26,6 @@
 import android.os.Build
 import android.view.animation.Interpolator
 import com.android.app.animation.Interpolators
-import com.android.launcher3.Launcher
 import com.android.launcher3.R
 import com.android.launcher3.Utilities
 import com.android.quickstep.util.AnimUtils
@@ -55,7 +54,7 @@
         private val ARRAY_OF_ZEROES = FloatArray(8)
     }
 
-    private val launcher: Launcher
+    private val container: RecentsViewContainer
     private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
 
     // Animation interpolators
@@ -70,15 +69,15 @@
     private val desiredSplitRatio: Float
 
     init {
-        launcher = Launcher.getLauncher(context)
-        val dp = launcher.deviceProfile
+        container = RecentsViewContainer.containerFromContext(context)
+        val dp = container.deviceProfile
         // Set up background paint color
         val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview)
         backgroundPaint.style = Paint.Style.FILL
         backgroundPaint.color = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0)
         ta.recycle()
         // Set up timings and interpolators
-        val timings = AnimUtils.getDeviceAppPairLaunchTimings(launcher.deviceProfile.isTablet)
+        val timings = AnimUtils.getDeviceAppPairLaunchTimings(container.deviceProfile.isTablet)
         expandXInterpolator =
             Interpolators.clampToProgress(
                 timings.getStagedRectScaleXInterpolator(),
@@ -105,9 +104,9 @@
             )
 
         // Find device-specific measurements
-        deviceCornerRadius = QuickStepContract.getWindowCornerRadius(launcher)
+        deviceCornerRadius = QuickStepContract.getWindowCornerRadius(container.asContext())
         deviceHalfDividerSize =
-            launcher.resources.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2f
+                container.asContext().resources.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2f
         val dividerCenterPos = dividerPos + deviceHalfDividerSize
         desiredSplitRatio =
             if (dp.isLeftRightSplit) dividerCenterPos / dp.widthPx
@@ -115,7 +114,7 @@
     }
 
     override fun draw(canvas: Canvas) {
-        if (launcher.deviceProfile.isLandscape) {
+        if (container.deviceProfile.isLeftRightSplit) {
             drawLeftRightSplit(canvas)
         } else {
             drawTopBottomSplit(canvas)
@@ -150,39 +149,37 @@
         val dividerCenterPos = width * desiredSplitRatio
 
         // The left half of the background image
-        val leftSide = RectF(
-            0f,
-            0f,
-            dividerCenterPos - changingDividerSize,
-            height
-        )
+        val leftSide = RectF(0f, 0f, dividerCenterPos - changingDividerSize, height)
         // The right half of the background image
-        val rightSide = RectF(
-            dividerCenterPos + changingDividerSize,
-            0f,
-            width,
-            height
-        )
+        val rightSide = RectF(dividerCenterPos + changingDividerSize, 0f, width, height)
 
         // Draw background
         drawCustomRoundedRect(
             canvas,
             leftSide,
             floatArrayOf(
-                cornerRadiusX, cornerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY,
-                cornerRadiusX, cornerRadiusY
+                cornerRadiusX,
+                cornerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY,
             )
         )
         drawCustomRoundedRect(
             canvas,
             rightSide,
             floatArrayOf(
-                changingInnerRadiusX, changingInnerRadiusY,
-                cornerRadiusX, cornerRadiusY,
-                cornerRadiusX, cornerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY,
             )
         )
 
@@ -250,39 +247,37 @@
         val dividerCenterPos = height * desiredSplitRatio
 
         // The top half of the background image
-        val topSide = RectF(
-            0f,
-            0f,
-            width,
-            dividerCenterPos - changingDividerSize
-        )
+        val topSide = RectF(0f, 0f, width, dividerCenterPos - changingDividerSize)
         // The bottom half of the background image
-        val bottomSide = RectF(
-            0f,
-            dividerCenterPos + changingDividerSize,
-            width,
-            height
-        )
+        val bottomSide = RectF(0f, dividerCenterPos + changingDividerSize, width, height)
 
         // Draw background
         drawCustomRoundedRect(
             canvas,
             topSide,
             floatArrayOf(
-                cornerRadiusX, cornerRadiusY,
-                cornerRadiusX, cornerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY
+                cornerRadiusX,
+                cornerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY
             )
         )
         drawCustomRoundedRect(
             canvas,
             bottomSide,
             floatArrayOf(
-                changingInnerRadiusX, changingInnerRadiusY,
-                changingInnerRadiusX, changingInnerRadiusY,
-                cornerRadiusX, cornerRadiusY,
-                cornerRadiusX, cornerRadiusY
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                changingInnerRadiusX,
+                changingInnerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY,
+                cornerRadiusX,
+                cornerRadiusY
             )
         )
 
@@ -338,8 +333,10 @@
             // Fallback rectangle with uniform rounded corners
             val scaleFactorX = floatingView.scaleX
             val scaleFactorY = floatingView.scaleY
-            val cornerRadiusX = QuickStepContract.getWindowCornerRadius(launcher) / scaleFactorX
-            val cornerRadiusY = QuickStepContract.getWindowCornerRadius(launcher) / scaleFactorY
+            val cornerRadiusX =
+                QuickStepContract.getWindowCornerRadius(container.asContext()) / scaleFactorX
+            val cornerRadiusY =
+                QuickStepContract.getWindowCornerRadius(container.asContext()) / scaleFactorY
             c.drawRoundRect(rect, cornerRadiusX, cornerRadiusY, backgroundPaint)
         }
     }
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index efc0a35..0e451b5 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -36,16 +36,14 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.AnimUtils;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.SplitAnimationTimings;
@@ -54,7 +52,7 @@
 
 /**
  * Create an instance via
- * {@link #getFloatingTaskView(StatefulActivity, View, Bitmap, Drawable, RectF)} to
+ * {@link #getFloatingTaskView(RecentsViewContainer, View, Bitmap, Drawable, RectF)} to
  * which will have the thumbnail from the provided existing TaskView overlaying the taskview itself.
  *
  * Can then animate the taskview using
@@ -67,35 +65,35 @@
 
     public static final FloatProperty<FloatingTaskView> PRIMARY_TRANSLATE_OFFSCREEN =
             new FloatProperty<FloatingTaskView>("floatingTaskPrimaryTranslateOffscreen") {
-        @Override
-        public void setValue(FloatingTaskView view, float translation) {
-            ((RecentsView) view.mActivity.getOverviewPanel()).getPagedOrientationHandler()
-                    .setFloatingTaskPrimaryTranslation(
-                            view,
-                            translation,
-                            view.mActivity.getDeviceProfile()
-                    );
-        }
+                @Override
+                public void setValue(FloatingTaskView view, float translation) {
+                    ((RecentsView) view.mContainer.getOverviewPanel()).getPagedOrientationHandler()
+                            .setFloatingTaskPrimaryTranslation(
+                                    view,
+                                    translation,
+                                    view.mContainer.getDeviceProfile()
+                            );
+                }
 
-        @Override
-        public Float get(FloatingTaskView view) {
-            return ((RecentsView) view.mActivity.getOverviewPanel())
-                    .getPagedOrientationHandler()
-                    .getFloatingTaskPrimaryTranslation(
-                            view,
-                            view.mActivity.getDeviceProfile()
-                    );
-        }
-    };
+                @Override
+                public Float get(FloatingTaskView view) {
+                        return ((RecentsView) view.mContainer.getOverviewPanel())
+                                .getPagedOrientationHandler()
+                                .getFloatingTaskPrimaryTranslation(
+                                        view,
+                                        view.mContainer.getDeviceProfile()
+                                );
+                }
+            };
 
     private int mSplitHolderSize;
     private FloatingTaskThumbnailView mThumbnailView;
     private SplitPlaceholderView mSplitPlaceholderView;
     private RectF mStartingPosition;
-    private final StatefulActivity mActivity;
+    private final RecentsViewContainer mContainer;
     private final boolean mIsRtl;
     private final FullscreenDrawParams mFullscreenParams;
-    private PagedOrientationHandler mOrientationHandler;
+    private RecentsPagedOrientationHandler mOrientationHandler;
     @SplitConfigurationOptions.StagePosition
     private int mStagePosition;
     private final Rect mTmpRect = new Rect();
@@ -110,7 +108,7 @@
 
     public FloatingTaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mActivity = BaseActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
         mIsRtl = Utilities.isRtl(getResources());
         mFullscreenParams = new FullscreenDrawParams(context);
 
@@ -126,7 +124,7 @@
         mSplitPlaceholderView.setAlpha(0);
     }
 
-    private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
+    private void init(RecentsViewContainer launcher, View originalView, @Nullable Bitmap thumbnail,
             Drawable icon, RectF positionOut) {
         mStartingPosition = positionOut;
         updateInitialPositionForView(originalView);
@@ -153,7 +151,7 @@
      * Configures and returns a an instance of {@link FloatingTaskView} initially matching the
      * appearance of {@code originalView}.
      */
-    public static FloatingTaskView getFloatingTaskView(StatefulActivity launcher,
+    public static FloatingTaskView getFloatingTaskView(RecentsViewContainer launcher,
             View originalView, @Nullable Bitmap thumbnail, Drawable icon, RectF positionOut) {
         final ViewGroup dragLayer = launcher.getDragLayer();
         final FloatingTaskView floatingView = (FloatingTaskView) launcher.getLayoutInflater()
@@ -167,7 +165,7 @@
             // Add to top if not
             openTaskViewIndex = dragLayer.getChildCount();
         }
-        dragLayer.addView(floatingView, openTaskViewIndex - 1);
+        dragLayer.addView(floatingView, openTaskViewIndex);
         return floatingView;
     }
 
@@ -179,13 +177,13 @@
             originalView.getBoundsOnScreen(mTmpRect);
             mStartingPosition.set(mTmpRect);
             int[] dragLayerPositionRelativeToScreen =
-                    mActivity.getDragLayer().getLocationOnScreen();
+                    mContainer.getDragLayer().getLocationOnScreen();
             mStartingPosition.offset(
                     -dragLayerPositionRelativeToScreen[0],
                     -dragLayerPositionRelativeToScreen[1]);
         } else {
             Rect viewBounds = new Rect(0, 0, originalView.getWidth(), originalView.getHeight());
-            Utilities.getBoundsForViewInDragLayer(mActivity.getDragLayer(), originalView,
+            Utilities.getBoundsForViewInDragLayer(mContainer.getDragLayer(), originalView,
                     viewBounds, false /* ignoreTransform */, null /* recycle */,
                     mStartingPosition);
         }
@@ -220,7 +218,7 @@
         mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIconView(), childScaleY);
     }
 
-    public void updateOrientationHandler(PagedOrientationHandler orientationHandler) {
+    public void updateOrientationHandler(RecentsPagedOrientationHandler orientationHandler) {
         mOrientationHandler = orientationHandler;
         mSplitPlaceholderView.getIconView().setRotation(mOrientationHandler.getDegreesRotated());
     }
@@ -235,7 +233,7 @@
         // Position the floating view exactly on top of the original
         lp.topMargin = Math.round(pos.top);
         if (mIsRtl) {
-            lp.setMarginStart(mActivity.getDeviceProfile().widthPx - Math.round(pos.right));
+            lp.setMarginStart(mContainer.getDeviceProfile().widthPx - Math.round(pos.right));
         } else {
             lp.setMarginStart(Math.round(pos.left));
         }
@@ -252,7 +250,7 @@
      */
     public void addStagingAnimation(PendingAnimation animation, RectF startingBounds,
             Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) {
-        boolean isTablet = mActivity.getDeviceProfile().isTablet;
+        boolean isTablet = mContainer.getDeviceProfile().isTablet;
         boolean splittingFromOverview = fadeWithThumbnail;
         SplitAnimationTimings timings;
 
@@ -276,7 +274,7 @@
     public void addConfirmAnimation(PendingAnimation animation, RectF startingBounds,
             Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask) {
         SplitAnimationTimings timings =
-                AnimUtils.getDeviceSplitToConfirmTimings(mActivity.getDeviceProfile().isTablet);
+                AnimUtils.getDeviceSplitToConfirmTimings(mContainer.getDeviceProfile().isTablet);
 
         addAnimation(animation, startingBounds, endBounds, fadeWithThumbnail, isStagedTask,
                 timings);
@@ -291,7 +289,7 @@
             Rect endBounds, boolean fadeWithThumbnail, boolean isStagedTask,
             SplitAnimationTimings timings) {
         mFullscreenParams.setIsStagedTask(isStagedTask);
-        final BaseDragLayer dragLayer = mActivity.getDragLayer();
+        final BaseDragLayer dragLayer = mContainer.getDragLayer();
         int[] dragLayerBounds = new int[2];
         dragLayer.getLocationOnScreen(dragLayerBounds);
         SplitOverlayProperties prop = new SplitOverlayProperties(endBounds,
@@ -299,7 +297,6 @@
 
         ValueAnimator transitionAnimator = ValueAnimator.ofFloat(0, 1);
         animation.add(transitionAnimator);
-        long animDuration = animation.getDuration();
         RectF floatingTaskViewBounds = new RectF();
 
         if (fadeWithThumbnail) {
@@ -328,20 +325,20 @@
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
             // SplitPlaceholderView: rectangle translates and stretches to new position
-            final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration,
+            final FloatProp mDx = new FloatProp(0, prop.dX,
                     clampToProgress(timings.getStagedRectXInterpolator(),
                             timings.getStagedRectSlideStartOffset(),
                             timings.getStagedRectSlideEndOffset()));
-            final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration,
+            final FloatProp mDy = new FloatProp(0, prop.dY,
                     clampToProgress(timings.getStagedRectYInterpolator(),
                             timings.getStagedRectSlideStartOffset(),
                             timings.getStagedRectSlideEndOffset()));
-            final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
-                    animDuration, clampToProgress(timings.getStagedRectScaleXInterpolator(),
+            final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX,
+                    clampToProgress(timings.getStagedRectScaleXInterpolator(),
                     timings.getStagedRectSlideStartOffset(),
                     timings.getStagedRectSlideEndOffset()));
-            final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY, 0,
-                    animDuration, clampToProgress(timings.getStagedRectScaleYInterpolator(),
+            final FloatProp mTaskViewScaleY = new FloatProp(1f, prop.finalTaskViewScaleY,
+                    clampToProgress(timings.getStagedRectScaleYInterpolator(),
                     timings.getStagedRectSlideStartOffset(),
                     timings.getStagedRectSlideEndOffset()));
             @Override
@@ -391,7 +388,7 @@
         mOrientationHandler.updateSplitIconParams(iconView, onScreenRectCenterX,
                 onScreenRectCenterY, mFullscreenParams.mScaleX, mFullscreenParams.mScaleY,
                 iconView.getDrawableWidth(), iconView.getDrawableHeight(),
-                mActivity.getDeviceProfile(), mStagePosition);
+                mContainer.getDeviceProfile(), mStagePosition);
     }
 
     public int getStagePosition() {
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 6431bdf..4dde635 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -33,10 +33,10 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.FloatingView;
 import com.android.launcher3.views.ListenerView;
@@ -49,7 +49,7 @@
         OnGlobalLayoutListener, FloatingView {
     private static final Matrix sTmpMatrix = new Matrix();
 
-    private final Launcher mLauncher;
+    private final QuickstepLauncher mLauncher;
     private final ListenerView mListenerView;
     private final FloatingWidgetBackgroundView mBackgroundView;
     private final RectF mBackgroundOffset = new RectF();
@@ -80,7 +80,7 @@
 
     public FloatingWidgetView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mLauncher = Launcher.getLauncher(context);
+        mLauncher = QuickstepLauncher.getLauncher(context);
         mListenerView = new ListenerView(context, attrs);
         mBackgroundView = new FloatingWidgetBackgroundView(context, attrs, defStyleAttr);
         addView(mBackgroundView);
@@ -283,7 +283,7 @@
      * @param windowSize               the size of the window when launched
      * @param windowCornerRadius       the corner radius of the window
      */
-    public static FloatingWidgetView getFloatingWidgetView(Launcher launcher,
+    public static FloatingWidgetView getFloatingWidgetView(QuickstepLauncher launcher,
             LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition,
             Size windowSize, float windowCornerRadius, boolean appTargetsAreTranslucent,
             int fallbackBackgroundColor) {
@@ -305,7 +305,8 @@
      */
     public static int getDefaultBackgroundColor(
             Context context, RemoteAnimationTarget target) {
-        return (target != null && target.taskInfo.taskDescription != null)
+        return (target != null && target.taskInfo != null
+                && target.taskInfo.taskDescription != null)
                 ? target.taskInfo.taskDescription.getBackgroundColor()
                 : Themes.getColorBackground(context);
     }
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index dd201af..9e1c856 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -7,19 +7,25 @@
 import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
 import android.content.Context;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewStub;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
@@ -27,7 +33,6 @@
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.TaskIconCache;
 import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.systemui.shared.recents.model.Task;
@@ -36,11 +41,11 @@
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
 
+import kotlin.Unit;
+
 import java.util.HashMap;
 import java.util.function.Consumer;
 
-import kotlin.Unit;
-
 /**
  * TaskView that contains and shows thumbnails for not one, BUT TWO(!!) tasks
  *
@@ -76,7 +81,7 @@
 
     public GroupedTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mDigitalWellBeingToast2 = new DigitalWellBeingToast(mActivity, this);
+        mDigitalWellBeingToast2 = new DigitalWellBeingToast(mContainer, this);
     }
 
     @Override
@@ -246,12 +251,11 @@
         RunnableList endCallback = new RunnableList();
         RecentsView recentsView = getRecentsView();
         // Callbacks run from remote animation when recents animation not currently running
-        InteractionJankMonitorWrapper.begin(this,
-                InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Enter form GroupedTaskView");
+        InteractionJankMonitorWrapper.begin(this, Cuj.CUJ_SPLIT_SCREEN_ENTER,
+                "Enter form GroupedTaskView");
         launchTaskInternal(success -> {
             endCallback.executeAllAndDestroy();
-            InteractionJankMonitorWrapper.end(
-                    InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
         }, false /* freezeTaskList */, true /*launchingExistingTaskview*/);
 
 
@@ -352,7 +356,7 @@
         if (initSplitTaskId == INVALID_TASK_ID) {
             getPagedOrientationHandler().measureGroupedTaskViewThumbnailBounds(mSnapshotView,
                     mSnapshotView2, widthSize, heightSize, mSplitBoundsConfig,
-                    mActivity.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+                    mContainer.getDeviceProfile(), getLayoutDirection() == LAYOUT_DIRECTION_RTL);
             // Should we be having a separate translation step apart from the measuring above?
             // The following only applies to large screen for now, but for future reference
             // we'd want to abstract this out in PagedViewHandlers to get the primary/secondary
@@ -369,34 +373,47 @@
             container.getThumbnailView().measure(widthMeasureSpec,
                     View.MeasureSpec.makeMeasureSpec(
                             heightSize -
-                                    mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx,
+                                    mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx,
                             MeasureSpec.EXACTLY));
         }
         if (!enableOverviewIconMenu()) {
             updateIconPlacement();
-            return;
         }
-
-        if (getRecentsView() == null) {
-            return;
-        }
-
-        int iconMargins = getResources().getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_start_margin) * 2;
-        ((IconAppChipView) mIconView).setMaxWidth(mSnapshotView.getMeasuredWidth() - iconMargins);
-        ((IconAppChipView) mIconView2).setMaxWidth(mSnapshotView2.getMeasuredWidth() - iconMargins);
-        setOrientationState(getRecentsView().getPagedViewOrientedState());
     }
 
     @Override
     public void setOverlayEnabled(boolean overlayEnabled) {
-        // Intentional no-op to prevent setting smart actions overlay on thumbnails
+        if (FeatureFlags.enableAppPairs()) {
+            super.setOverlayEnabled(overlayEnabled);
+        } else {
+            // Intentional no-op to prevent setting smart actions overlay on thumbnails
+        }
     }
 
     @Override
     public void setOrientationState(RecentsOrientedState orientationState) {
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+        if (enableOverviewIconMenu() && mSplitBoundsConfig != null) {
+            ViewGroup.LayoutParams layoutParams = getLayoutParams();
+            Pair<Point, Point> groupedTaskViewSizes =
+                    orientationState.getOrientationHandler().getGroupedTaskViewSizes(
+                            deviceProfile,
+                            mSplitBoundsConfig,
+                            layoutParams.width,
+                            layoutParams.height
+                    );
+            int iconViewMarginStart = getResources().getDimensionPixelSize(
+                    R.dimen.task_thumbnail_icon_menu_expanded_top_start_margin);
+            int iconViewBackgroundMarginStart = getResources().getDimensionPixelSize(
+                    R.dimen.task_thumbnail_icon_menu_background_margin_top_start);
+            int iconMargins = (iconViewMarginStart + iconViewBackgroundMarginStart) * 2;
+            ((IconAppChipView) mIconView).setMaxWidth(groupedTaskViewSizes.first.x - iconMargins);
+            ((IconAppChipView) mIconView2).setMaxWidth(groupedTaskViewSizes.second.x - iconMargins);
+        }
+        // setMaxWidth() needs to be called before mIconView.setIconOrientation which is called in
+        // the super below.
         super.setOrientationState(orientationState);
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+
         boolean isGridTask = deviceProfile.isTablet && !isFocusedTask();
         mIconView2.setIconOrientation(orientationState, isGridTask);
         updateIconPlacement();
@@ -408,14 +425,31 @@
             return;
         }
 
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
 
-        getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
-                taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(),
-                getMeasuredHeight(), getMeasuredWidth(), isRtl, deviceProfile,
-                mSplitBoundsConfig);
+        if (enableOverviewIconMenu()) {
+            ViewGroup.LayoutParams layoutParams = getLayoutParams();
+            Pair<Point, Point> groupedTaskViewSizes =
+                    getPagedOrientationHandler()
+                            .getGroupedTaskViewSizes(
+                                    deviceProfile,
+                                    mSplitBoundsConfig,
+                                    layoutParams.width,
+                                    layoutParams.height
+                            );
+
+            getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
+                    taskIconHeight, groupedTaskViewSizes.first.x, groupedTaskViewSizes.first.y,
+                    getLayoutParams().height, getLayoutParams().width, isRtl, deviceProfile,
+                    mSplitBoundsConfig);
+        } else {
+            getPagedOrientationHandler().setSplitIconParams(mIconView.asView(), mIconView2.asView(),
+                    taskIconHeight, mSnapshotView.getMeasuredWidth(),
+                    mSnapshotView.getMeasuredHeight(), getMeasuredHeight(), getMeasuredWidth(),
+                    isRtl, deviceProfile, mSplitBoundsConfig);
+        }
     }
 
     private void updateSecondaryDwbPlacement() {
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
index ee09c4d..ba42594 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -17,31 +17,35 @@
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.Outline;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
-import android.view.Gravity;
 import android.view.View;
 import android.view.ViewAnimationUtils;
+import android.view.ViewOutlineProvider;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.RecentsOrientedState;
 
 /**
@@ -52,43 +56,90 @@
     private static final int MENU_BACKGROUND_REVEAL_DURATION = 417;
     private static final int MENU_BACKGROUND_HIDE_DURATION = 333;
 
-    private static final int NUM_ALPHA_CHANNELS = 2;
+    private static final int NUM_ALPHA_CHANNELS = 3;
     private static final int INDEX_CONTENT_ALPHA = 0;
     private static final int INDEX_COLOR_FILTER_ALPHA = 1;
+    private static final int INDEX_MODAL_ALPHA = 2;
 
     private final MultiValueAlpha mMultiValueAlpha;
 
+    private View mMenuAnchorView;
     private IconView mIconView;
     // Two textview so we can ellipsize the collapsed view and crossfade on expand to the full name.
     private TextView mIconTextCollapsedView;
     private TextView mIconTextExpandedView;
     private ImageView mIconArrowView;
-    private ImageView mIconViewBackground;
-    // Use separate views for the rounded corners so we can scale the background view without
-    // warping the corners.
-    private ImageView mIconViewBackgroundCornersStart;
-    private ImageView mIconViewBackgroundCornersEnd;
-
-    private final int mMinimumMenuSize;
-    private final int mMaxMenuWidth;
-    private final int mIconMenuMarginTop;
-    private final int mIconMenuMarginStart;
+    private final Rect mBackgroundRelativeLtrLocation = new Rect();
+    final RectEvaluator mBackgroundAnimationRectEvaluator =
+            new RectEvaluator(mBackgroundRelativeLtrLocation);
+    private final int mCollapsedMenuDefaultWidth;
+    private final int mExpandedMenuDefaultWidth;
+    private final int mCollapsedMenuDefaultHeight;
+    private final int mExpandedMenuDefaultHeight;
+    private final int mIconMenuMarginTopStart;
+    private final int mMenuToChipGap;
+    private final int mBackgroundMarginTopStart;
+    private final int mAppNameHorizontalMargin;
     private final int mIconViewMarginStart;
-    private final int mIconViewDrawableSize;
-    private final int mIconViewDrawableMaxSize;
-    private final int mIconTextMinWidth;
-    private final int mIconTextMaxWidth;
-    private final int mTextMaxTranslationX;
-    private final int mInnerMargin;
-    private final float mArrowMaxTranslationX;
-    private final int mMinIconBackgroundWidth;
-    private final int mMaxIconBackgroundHeight;
-    private final int mMinIconBackgroundHeight;
-    private final int mMaxIconBackgroundCornerRadius;
-    private final float mMinIconBackgroundCornerRadius;
+    private final int mAppIconSize;
+    private final int mArrowSize;
+    private final int mIconViewDrawableExpandedSize;
+    private final int mArrowMarginEnd;
+    private AnimatorSet mAnimator;
 
     private int mMaxWidth = Integer.MAX_VALUE;
 
+    private static final int INDEX_SPLIT_TRANSLATION = 0;
+    private static final int INDEX_MENU_TRANSLATION = 1;
+    private static final int INDEX_COUNT_TRANSLATION = 2;
+
+    private final MultiPropertyFactory<View> mViewTranslationX;
+    private final MultiPropertyFactory<View> mViewTranslationY;
+
+    /**
+     * Gets the view split x-axis translation
+     */
+    public MultiPropertyFactory<View>.MultiProperty getSplitTranslationX() {
+        return mViewTranslationX.get(INDEX_SPLIT_TRANSLATION);
+    }
+
+    /**
+     * Sets the view split x-axis translation
+     * @param translationX x-axis translation
+     */
+    public void setSplitTranslationX(float translationX) {
+        getSplitTranslationX().setValue(translationX);
+    }
+
+    /**
+     * Gets the view split y-axis translation
+     */
+    public MultiPropertyFactory<View>.MultiProperty getSplitTranslationY() {
+        return mViewTranslationY.get(INDEX_SPLIT_TRANSLATION);
+    }
+
+    /**
+     * Sets the view split y-axis translation
+     * @param translationY y-axis translation
+     */
+    public void setSplitTranslationY(float translationY) {
+        getSplitTranslationY().setValue(translationY);
+    }
+
+    /**
+     * Gets the menu x-axis translation for split task
+     */
+    public MultiPropertyFactory<View>.MultiProperty getMenuTranslationX() {
+        return mViewTranslationX.get(INDEX_MENU_TRANSLATION);
+    }
+
+    /**
+     * Gets the menu y-axis translation for split task
+     */
+    public MultiPropertyFactory<View>.MultiProperty getMenuTranslationY() {
+        return mViewTranslationY.get(INDEX_MENU_TRANSLATION);
+    }
+
     public IconAppChipView(Context context) {
         this(context, null);
     }
@@ -109,51 +160,42 @@
         mMultiValueAlpha.setUpdateVisibility(/* updateVisibility= */ true);
 
         // Menu dimensions
-        mMaxMenuWidth = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_max_width);
-        mIconMenuMarginTop = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_top_margin);
-        mIconMenuMarginStart = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_start_margin);
+        mCollapsedMenuDefaultWidth =
+                res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_collapsed_width);
+        mExpandedMenuDefaultWidth =
+                res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_expanded_width);
+        mCollapsedMenuDefaultHeight =
+                res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_collapsed_height);
+        mExpandedMenuDefaultHeight =
+                res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_expanded_height);
+        mIconMenuMarginTopStart = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_expanded_top_start_margin);
+        mMenuToChipGap = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_expanded_gap);
 
         // Background dimensions
-        mMinIconBackgroundWidth = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_background_min_width);
-        mMaxIconBackgroundHeight = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_max_height);
-        mMinIconBackgroundHeight = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_min_height);
-        mMaxIconBackgroundCornerRadius = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_corner_radius);
+        mBackgroundMarginTopStart = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_background_margin_top_start);
 
-        // TextView dimensions
-        mInnerMargin = (int) res.getDimension(R.dimen.task_thumbnail_icon_menu_arrow_margin);
-        mIconTextMinWidth = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_text_width);
-        mIconTextMaxWidth = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_text_max_width);
-
-        // IconView dimensions
+        // Contents dimensions
+        mAppNameHorizontalMargin = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_app_name_margin_horizontal_collapsed);
+        mArrowMarginEnd = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_arrow_margin);
         mIconViewMarginStart = res.getDimensionPixelSize(
                 R.dimen.task_thumbnail_icon_view_start_margin);
-        mIconViewDrawableSize = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_drawable_size);
-        mIconViewDrawableMaxSize = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_drawable_max_size);
-        mTextMaxTranslationX =
-                (mIconViewDrawableMaxSize - mIconViewDrawableSize - mIconViewMarginStart)
-                        + (mInnerMargin / 2);
-
-        // ArrowView dimensions
-        int iconArrowViewWidth = res.getDimensionPixelSize(
+        mAppIconSize = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_app_icon_collapsed_size);
+        mArrowSize = res.getDimensionPixelSize(
                 R.dimen.task_thumbnail_icon_menu_arrow_size);
-        mMinIconBackgroundCornerRadius = mMinIconBackgroundHeight / 2f;
-        float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f,
-                mMaxIconBackgroundCornerRadius);
-        mArrowMaxTranslationX = (mMaxMenuWidth - maxCornerSize) - (Math.min(mMaxWidth,
-                mMinIconBackgroundWidth + (2 * mMinIconBackgroundCornerRadius)
-                        - mMinIconBackgroundCornerRadius)) - mInnerMargin;
+        mIconViewDrawableExpandedSize = res.getDimensionPixelSize(
+                R.dimen.task_thumbnail_icon_menu_app_icon_expanded_size);
 
-        // Menu dimensions
-        mMinimumMenuSize =
-                mIconViewMarginStart + mIconViewDrawableSize + mInnerMargin + iconArrowViewWidth;
+        mViewTranslationX = new MultiPropertyFactory<>(this, VIEW_TRANSLATE_X,
+                INDEX_COUNT_TRANSLATION,
+                Float::sum);
+        mViewTranslationY = new MultiPropertyFactory<>(this, VIEW_TRANSLATE_Y,
+                INDEX_COUNT_TRANSLATION,
+                Float::sum);
     }
 
     @Override
@@ -163,9 +205,7 @@
         mIconTextCollapsedView = findViewById(R.id.icon_text_collapsed);
         mIconTextExpandedView = findViewById(R.id.icon_text_expanded);
         mIconArrowView = findViewById(R.id.icon_arrow);
-        mIconViewBackground = findViewById(R.id.icon_view_background);
-        mIconViewBackgroundCornersStart = findViewById(R.id.icon_view_background_corners_start);
-        mIconViewBackgroundCornersEnd = findViewById(R.id.icon_view_background_corners_end);
+        mMenuAnchorView = findViewById(R.id.icon_view_menu_anchor);
     }
 
     protected IconView getIconView() {
@@ -202,87 +242,86 @@
     }
 
     /**
-     * Sets the maximum width of this Icon Menu.
+     * Sets the maximum width of this Icon Menu. This is usually used when space is limited for
+     * split screen.
      */
     public void setMaxWidth(int maxWidth) {
-        // Only the app icon and caret are visible at its minimum width.
-        mMaxWidth = Math.max(maxWidth, mMinimumMenuSize);
+        // Width showing only the app icon and arrow. Max width should not be set to less than this.
+        int minimumMaxWidth = mIconViewMarginStart + mAppIconSize + mArrowSize + mArrowMarginEnd;
+        mMaxWidth = Math.max(maxWidth, minimumMaxWidth);
     }
 
     @Override
     public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
-        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
-        boolean isRtl = isLayoutRtl();
-        DeviceProfile deviceProfile =
-                ActivityContext.lookupContext(getContext()).getDeviceProfile();
+        RecentsPagedOrientationHandler orientationHandler =
+                orientationState.getOrientationHandler();
+        // Layout params for anchor view
+        LayoutParams anchorLayoutParams = (LayoutParams) mMenuAnchorView.getLayoutParams();
+        anchorLayoutParams.topMargin = mExpandedMenuDefaultHeight + mMenuToChipGap;
+        mMenuAnchorView.setLayoutParams(anchorLayoutParams);
 
-        // Layout Params for the Menu View
-        int thumbnailTopMargin =
-                deviceProfile.overviewTaskThumbnailTopMarginPx + mIconMenuMarginTop;
+        // Layout Params for the Menu View (this)
         LayoutParams iconMenuParams = (LayoutParams) getLayoutParams();
-        orientationHandler.setIconAppChipMenuParams(this, iconMenuParams, mIconMenuMarginStart,
-                thumbnailTopMargin);
-        iconMenuParams.width = Math.min(mMaxWidth,
-                mMinIconBackgroundWidth + (int) (2 * mMinIconBackgroundCornerRadius));
-        iconMenuParams.height = mMinIconBackgroundHeight;
+        iconMenuParams.width = mExpandedMenuDefaultWidth;
+        iconMenuParams.height = mExpandedMenuDefaultHeight;
+        orientationHandler.setIconAppChipMenuParams(this, iconMenuParams, mIconMenuMarginTopStart,
+                mIconMenuMarginTopStart);
         setLayoutParams(iconMenuParams);
 
+        // Layout params for the background
+        Rect collapsedBackgroundBounds = getCollapsedBackgroundLtrBounds();
+        mBackgroundRelativeLtrLocation.set(collapsedBackgroundBounds);
+        setOutlineProvider(new ViewOutlineProvider() {
+            final Rect mRtlAppliedOutlineBounds = new Rect();
+            @Override
+            public void getOutline(View view, Outline outline) {
+                mRtlAppliedOutlineBounds.set(mBackgroundRelativeLtrLocation);
+                if (isLayoutRtl()) {
+                    int width = getWidth();
+                    mRtlAppliedOutlineBounds.left = width - mBackgroundRelativeLtrLocation.right;
+                    mRtlAppliedOutlineBounds.right = width - mBackgroundRelativeLtrLocation.left;
+                }
+                outline.setRoundRect(
+                        mRtlAppliedOutlineBounds, mRtlAppliedOutlineBounds.height() / 2f);
+            }
+        });
+
         // Layout Params for the Icon View
         LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-        orientationHandler.setTaskIconParams(iconParams, mIconViewMarginStart,
-                mIconViewDrawableSize, thumbnailTopMargin, isRtl);
-        iconParams.width = iconParams.height = mIconViewDrawableSize;
+        int iconMarginStartRelativeToParent = mIconViewMarginStart + mBackgroundMarginTopStart;
+        orientationHandler.setIconAppChipChildrenParams(
+                iconParams, iconMarginStartRelativeToParent);
+
         mIconView.setLayoutParams(iconParams);
-        mIconView.setDrawableSize(mIconViewDrawableSize, mIconViewDrawableSize);
+        mIconView.setDrawableSize(mAppIconSize, mAppIconSize);
 
         // Layout Params for the collapsed Icon Text View
+        int textMarginStart =
+                iconMarginStartRelativeToParent + mAppIconSize + mAppNameHorizontalMargin;
         LayoutParams iconTextCollapsedParams =
                 (LayoutParams) mIconTextCollapsedView.getLayoutParams();
-        orientationHandler.setTaskIconParams(iconTextCollapsedParams, 0, mIconViewDrawableSize,
-                thumbnailTopMargin, isRtl);
-        iconTextCollapsedParams.setMarginStart(
-                mIconViewDrawableSize + mIconViewMarginStart + mInnerMargin);
-        iconTextCollapsedParams.topMargin = (mMinIconBackgroundHeight - mIconViewDrawableSize) / 2;
-        iconTextCollapsedParams.gravity = Gravity.TOP | Gravity.START;
-        iconTextCollapsedParams.width = Math.min(
-                Math.max(mMaxWidth - mMinimumMenuSize - (2 * mInnerMargin), 0), mIconTextMinWidth);
+        orientationHandler.setIconAppChipChildrenParams(iconTextCollapsedParams, textMarginStart);
+        int collapsedTextWidth = collapsedBackgroundBounds.width() - mIconViewMarginStart
+                - mAppIconSize - mArrowSize - mAppNameHorizontalMargin - mArrowMarginEnd;
+        iconTextCollapsedParams.width = collapsedTextWidth;
         mIconTextCollapsedView.setLayoutParams(iconTextCollapsedParams);
         mIconTextCollapsedView.setAlpha(1f);
 
         // Layout Params for the expanded Icon Text View
         LayoutParams iconTextExpandedParams =
                 (LayoutParams) mIconTextExpandedView.getLayoutParams();
-        orientationHandler.setTaskIconParams(iconTextExpandedParams, 0, mIconViewDrawableSize,
-                thumbnailTopMargin, isRtl);
-        iconTextExpandedParams.setMarginStart(
-                mIconViewDrawableSize + mIconViewMarginStart + mInnerMargin);
-        iconTextExpandedParams.topMargin = (mMinIconBackgroundHeight - mIconViewDrawableSize) / 2;
-        iconTextExpandedParams.gravity = Gravity.TOP | Gravity.START;
+        orientationHandler.setIconAppChipChildrenParams(iconTextExpandedParams, textMarginStart);
         mIconTextExpandedView.setLayoutParams(iconTextExpandedParams);
         mIconTextExpandedView.setAlpha(0f);
-        mIconTextExpandedView.setRevealClip(true, 0, mIconViewDrawableSize / 2f, mIconTextMinWidth);
+        mIconTextExpandedView.setRevealClip(true, 0, mAppIconSize / 2f, collapsedTextWidth);
 
         // Layout Params for the Icon Arrow View
         LayoutParams iconArrowParams = (LayoutParams) mIconArrowView.getLayoutParams();
-        iconArrowParams.gravity = Gravity.CENTER_VERTICAL | Gravity.END;
-        iconArrowParams.setMarginEnd(mInnerMargin);
+        int arrowMarginStart = collapsedBackgroundBounds.right - mArrowMarginEnd - mArrowSize;
+        orientationHandler.setIconAppChipChildrenParams(iconArrowParams, arrowMarginStart);
+        mIconArrowView.setPivotY(iconArrowParams.height / 2f);
         mIconArrowView.setLayoutParams(iconArrowParams);
 
-        // Layout Params for the Icon View Background and its corners
-        int cornerlessBackgroundWidth = (int) Math.min(
-                mMaxWidth - (2 * mMinIconBackgroundCornerRadius), mMinIconBackgroundWidth);
-        LayoutParams backgroundCornerEndParams =
-                (LayoutParams) mIconViewBackgroundCornersEnd.getLayoutParams();
-        backgroundCornerEndParams.setMarginStart(cornerlessBackgroundWidth);
-        mIconViewBackgroundCornersEnd.setLayoutParams(backgroundCornerEndParams);
-        LayoutParams backgroundParams = (LayoutParams) mIconViewBackground.getLayoutParams();
-        backgroundParams.width = cornerlessBackgroundWidth;
-        backgroundParams.height = mMinIconBackgroundHeight;
-        backgroundParams.setMarginStart((int) mMinIconBackgroundCornerRadius);
-        mIconViewBackground.setLayoutParams(backgroundParams);
-        mIconViewBackground.setPivotX(isRtl ? cornerlessBackgroundWidth : 0);
-        mIconViewBackground.setPivotY(mMinIconBackgroundCornerRadius);
-
         // This method is called twice sometimes (like when rotating split tasks). It is called
         // once before onMeasure and onLayout, and again after onMeasure but before onLayout with
         // a new width. This happens because we update widths on rotation and on measure of
@@ -305,6 +344,11 @@
     }
 
     @Override
+    public void setModalAlpha(float alpha) {
+        mMultiValueAlpha.get(INDEX_MODAL_ALPHA).setValue(alpha);
+    }
+
+    @Override
     public int getDrawableWidth() {
         return mIconView == null ? 0 : mIconView.getDrawableWidth();
     }
@@ -315,115 +359,102 @@
     }
 
     protected void revealAnim(boolean isRevealing) {
+        cancelInProgressAnimations();
+        final Rect collapsedBackgroundBounds = getCollapsedBackgroundLtrBounds();
+        final Rect expandedBackgroundBounds = getExpandedBackgroundLtrBounds();
+        final Rect initialBackground = new Rect(mBackgroundRelativeLtrLocation);
+        mAnimator = new AnimatorSet();
+
         if (isRevealing) {
             boolean isRtl = isLayoutRtl();
             bringToFront();
-            ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start();
-            AnimatorSet anim = new AnimatorSet();
-            float backgroundScaleY = mMaxIconBackgroundHeight / (float) mMinIconBackgroundHeight;
-            float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f,
-                    mMaxIconBackgroundCornerRadius);
-            float backgroundScaleX = (mMaxMenuWidth - (2 * maxCornerSize)) / Math.min(
-                    mMaxWidth - (2 * mMinIconBackgroundCornerRadius), mMinIconBackgroundWidth);
-            float arrowTranslationX = mArrowMaxTranslationX + (mMinIconBackgroundWidth - Math.min(
-                    mMaxWidth - (2 * mMinIconBackgroundCornerRadius), mMinIconBackgroundWidth));
             // Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu
             Animator expandedTextRevealAnim = ViewAnimationUtils.createCircularReveal(
-                    mIconTextExpandedView, 0, mIconTextExpandedView.getHeight() / 2, 0,
-                    mIconTextMaxWidth + maxCornerSize);
-            expandedTextRevealAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    // createCircularReveal removes clip on finish, restore it here to clip text.
-                    mIconTextExpandedView.setRevealClip(true, 0,
-                            mIconTextExpandedView.getHeight() / 2f,
-                            mIconTextMaxWidth + maxCornerSize);
-                }
-            });
-            anim.playTogether(
+                    mIconTextExpandedView, 0, mIconTextExpandedView.getHeight() / 2,
+                    mIconTextCollapsedView.getWidth(), mIconTextExpandedView.getWidth());
+            // Animate background clipping
+            ValueAnimator backgroundAnimator = ValueAnimator.ofObject(
+                    mBackgroundAnimationRectEvaluator,
+                    initialBackground,
+                    expandedBackgroundBounds);
+            backgroundAnimator.addUpdateListener(valueAnimator -> invalidateOutline());
+
+            float iconViewScaling = mIconViewDrawableExpandedSize / (float) mAppIconSize;
+            float arrowTranslationX =
+                    expandedBackgroundBounds.right - collapsedBackgroundBounds.right;
+            float iconCenterToTextCollapsed = mAppIconSize / 2f + mAppNameHorizontalMargin;
+            float iconCenterToTextExpanded =
+                    mIconViewDrawableExpandedSize / 2f + mAppNameHorizontalMargin;
+            float textTranslationX = iconCenterToTextExpanded - iconCenterToTextCollapsed;
+
+            float textTranslationXWithRtl = isRtl ? -textTranslationX : textTranslationX;
+            float arrowTranslationWithRtl = isRtl ? -arrowTranslationX : arrowTranslationX;
+
+            mAnimator.playTogether(
                     expandedTextRevealAnim,
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y,
-                            backgroundScaleY),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_X,
-                            backgroundScaleY),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, SCALE_Y,
-                            backgroundScaleY),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, SCALE_X,
-                            backgroundScaleY),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, TRANSLATION_X,
-                            isRtl ? -arrowTranslationX : arrowTranslationX),
-                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X, backgroundScaleX),
-                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y, backgroundScaleY),
-                    ObjectAnimator.ofFloat(mIconView, SCALE_X,
-                            mIconViewDrawableMaxSize / (float) mIconViewDrawableSize),
-                    ObjectAnimator.ofFloat(mIconView, SCALE_Y,
-                            mIconViewDrawableMaxSize / (float) mIconViewDrawableSize),
+                    backgroundAnimator,
+                    ObjectAnimator.ofFloat(mIconView, SCALE_X, iconViewScaling),
+                    ObjectAnimator.ofFloat(mIconView, SCALE_Y, iconViewScaling),
                     ObjectAnimator.ofFloat(mIconTextCollapsedView, TRANSLATION_X,
-                            isLayoutRtl() ? -mTextMaxTranslationX : mTextMaxTranslationX),
+                            textTranslationXWithRtl),
                     ObjectAnimator.ofFloat(mIconTextExpandedView, TRANSLATION_X,
-                            isLayoutRtl() ? -mTextMaxTranslationX : mTextMaxTranslationX),
+                            textTranslationXWithRtl),
                     ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 0),
                     ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 1),
-                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X,
-                            isRtl ? -arrowTranslationX : arrowTranslationX));
-            anim.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
-            anim.setInterpolator(EMPHASIZED);
-            anim.start();
+                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, arrowTranslationWithRtl),
+                    ObjectAnimator.ofFloat(mIconArrowView, SCALE_Y, -1));
+            mAnimator.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
         } else {
-            ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse();
-            float maxCornerSize = Math.min(mMaxIconBackgroundHeight / 2f,
-                    mMaxIconBackgroundCornerRadius);
             // Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu
             Animator expandedTextClipAnim = ViewAnimationUtils.createCircularReveal(
                     mIconTextExpandedView, 0, mIconTextExpandedView.getHeight() / 2,
-                    mIconTextMaxWidth + maxCornerSize, 0);
-            expandedTextClipAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    // createCircularReveal removes clip on finish, restore it here to clip text.
-                    mIconTextExpandedView.setRevealClip(true, 0,
-                            mIconTextExpandedView.getHeight() / 2f, 0);
-                }
-            });
-            AnimatorSet anim = new AnimatorSet();
-            anim.playTogether(
+                    mIconTextExpandedView.getWidth(), mIconTextCollapsedView.getWidth());
+
+            // Animate background clipping
+            ValueAnimator backgroundAnimator = ValueAnimator.ofObject(
+                    mBackgroundAnimationRectEvaluator,
+                    initialBackground,
+                    collapsedBackgroundBounds);
+            backgroundAnimator.addUpdateListener(valueAnimator -> invalidateOutline());
+
+            mAnimator.playTogether(
                     expandedTextClipAnim,
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_X, 1),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersStart, SCALE_Y, 1),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, SCALE_X, 1),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, SCALE_Y, 1),
-                    ObjectAnimator.ofFloat(mIconViewBackgroundCornersEnd, TRANSLATION_X, 0),
-                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_X, 1),
-                    ObjectAnimator.ofFloat(mIconViewBackground, SCALE_Y, 1),
-                    ObjectAnimator.ofFloat(mIconView, SCALE_X, 1),
-                    ObjectAnimator.ofFloat(mIconView, SCALE_Y, 1),
+                    backgroundAnimator,
+                    ObjectAnimator.ofFloat(mIconView, SCALE_PROPERTY, 1),
                     ObjectAnimator.ofFloat(mIconTextCollapsedView, TRANSLATION_X, 0),
                     ObjectAnimator.ofFloat(mIconTextExpandedView, TRANSLATION_X, 0),
                     ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 1),
                     ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 0),
-                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0));
-            anim.setDuration(MENU_BACKGROUND_HIDE_DURATION);
-            anim.setInterpolator(EMPHASIZED);
-            anim.start();
+                    ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0),
+                    ObjectAnimator.ofFloat(mIconArrowView, SCALE_Y, 1));
+            mAnimator.setDuration(MENU_BACKGROUND_HIDE_DURATION);
         }
+
+        mAnimator.setInterpolator(EMPHASIZED);
+        mAnimator.start();
     }
 
-    protected void reset() {
-        mIconViewBackgroundCornersStart.setScaleX(1);
-        mIconViewBackgroundCornersStart.setScaleY(1);
-        mIconViewBackgroundCornersEnd.setScaleX(1);
-        mIconViewBackgroundCornersEnd.setScaleY(1);
-        mIconViewBackgroundCornersEnd.setTranslationX(0);
-        mIconViewBackground.setScaleX(1);
-        mIconViewBackground.setScaleY(1);
-        mIconView.setScaleX(1);
-        mIconView.setScaleY(1);
-        mIconTextCollapsedView.setTranslationX(0);
-        mIconTextExpandedView.setTranslationX(0);
-        mIconTextCollapsedView.setAlpha(1);
-        mIconTextExpandedView.setAlpha(0);
-        mIconArrowView.setTranslationX(0);
-        ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reset();
+    private Rect getCollapsedBackgroundLtrBounds() {
+        Rect bounds = new Rect(
+                0,
+                0,
+                Math.min(mMaxWidth, mCollapsedMenuDefaultWidth),
+                mCollapsedMenuDefaultHeight);
+        bounds.offset(mBackgroundMarginTopStart, mBackgroundMarginTopStart);
+        return bounds;
+    }
+
+    private Rect getExpandedBackgroundLtrBounds() {
+        return new Rect(0, 0, mExpandedMenuDefaultWidth, mExpandedMenuDefaultHeight);
+    }
+
+    private void cancelInProgressAnimations() {
+        // We null the `AnimatorSet` because it holds references to the `Animators` which aren't
+        // expecting to be mutable and will cause a crash if they are re-used.
+        if (mAnimator != null && mAnimator.isStarted()) {
+            mAnimator.cancel();
+            mAnimator = null;
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index a4bda7f..1312ec3 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -15,8 +15,6 @@
  */
 package com.android.quickstep.views;
 
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -30,8 +28,8 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.RecentsOrientedState;
 
 /**
@@ -149,6 +147,11 @@
     }
 
     @Override
+    public void setModalAlpha(float alpha) {
+        setAlpha(alpha);
+    }
+
+    @Override
     public void setAlpha(float alpha) {
         super.setAlpha(alpha);
         if (alpha > 0) {
@@ -173,7 +176,8 @@
 
     @Override
     public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
-        PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
+        RecentsPagedOrientationHandler orientationHandler =
+                orientationState.getOrientationHandler();
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         DeviceProfile deviceProfile =
                 ActivityContext.lookupContext(getContext()).getDeviceProfile();
@@ -190,10 +194,8 @@
         setLayoutParams(iconParams);
 
         setRotation(orientationHandler.getDegreesRotated());
-        int iconDrawableSize = enableOverviewIconMenu()
-                ? deviceProfile.overviewTaskIconAppChipMenuDrawableSizePx
-                : isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
-                        : deviceProfile.overviewTaskIconDrawableSizePx;
+        int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
+                : deviceProfile.overviewTaskIconDrawableSizePx;
         setDrawableSize(iconDrawableSize, iconDrawableSize);
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 5b5d0de..8d1907f 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -16,6 +16,7 @@
 package com.android.quickstep.views;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
@@ -24,13 +25,13 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.LauncherState.SPRING_LOADED;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
+import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
 
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.os.Build;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.MotionEvent;
 
 import androidx.annotation.Nullable;
@@ -44,7 +45,6 @@
 import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateListener;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.SplitConfigurationOptions;
@@ -73,7 +73,7 @@
 
     public LauncherRecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr, LauncherActivityInterface.INSTANCE);
-        mActivity.getStateManager().addStateListener(this);
+        getStateManager().addStateListener(this);
     }
 
     @Override
@@ -86,28 +86,33 @@
 
     @Override
     protected void handleStartHome(boolean animated) {
-        StateManager stateManager = mActivity.getStateManager();
+        StateManager stateManager = getStateManager();
         animated &= stateManager.shouldAnimateStateChange();
         stateManager.goToState(NORMAL, animated);
         if (FeatureFlags.enableSplitContextually()) {
             mSplitSelectStateController.getSplitAnimationController()
-                    .playPlaceholderDismissAnim(mActivity);
+                    .playPlaceholderDismissAnim(mContainer, LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
         }
-        AbstractFloatingView.closeAllOpenViews(mActivity, animated);
+        AbstractFloatingView.closeAllOpenViews(mContainer, animated);
     }
 
     @Override
     protected boolean canStartHomeSafely() {
-        return mActivity.canStartHomeSafely();
+        return mContainer.canStartHomeSafely();
+    }
+
+    @Override
+    public StateManager<LauncherState> getStateManager() {
+        return mContainer.getStateManager();
     }
 
     @Override
     protected void onTaskLaunchAnimationEnd(boolean success) {
         if (success) {
-            mActivity.getStateManager().moveToRestState();
+            getStateManager().moveToRestState();
         } else {
-            LauncherState state = mActivity.getStateManager().getState();
-            mActivity.getAllAppsController().setState(state);
+            LauncherState state = getStateManager().getState();
+            mContainer.getAllAppsController().setState(state);
         }
         super.onTaskLaunchAnimationEnd(success);
     }
@@ -116,14 +121,14 @@
     public void onTaskIconChanged(int taskId) {
         super.onTaskIconChanged(taskId);
         // If Launcher needs to return to split select state, do it now, after the icon has updated.
-        if (mActivity.hasPendingSplitSelectInfo()) {
-            PendingSplitSelectInfo recoveryData = mActivity.getPendingSplitSelectInfo();
+        if (mContainer.hasPendingSplitSelectInfo()) {
+            PendingSplitSelectInfo recoveryData = mContainer.getPendingSplitSelectInfo();
             if (recoveryData.getStagedTaskId() == taskId) {
                 initiateSplitSelect(
                         getTaskViewByTaskId(recoveryData.getStagedTaskId()),
                         recoveryData.getStagePosition(), recoveryData.getSource()
                 );
-                mActivity.finishSplitSelectRecovery();
+                mContainer.finishSplitSelectRecovery();
             }
         }
     }
@@ -140,10 +145,12 @@
     public void onStateTransitionStart(LauncherState toState) {
         setOverviewStateEnabled(toState.overviewUi);
 
-        setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
+        setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mContainer.getDeviceProfile()));
         setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
         if (toState == OVERVIEW_MODAL_TASK) {
             setOverviewSelectEnabled(true);
+        } else {
+            resetModalVisuals();
         }
 
         // Set border after select mode changes to avoid showing border during state transition
@@ -152,8 +159,8 @@
         }
 
         setFreezeViewVisibility(true);
-        if (mActivity.getDesktopVisibilityController() != null) {
-            mActivity.getDesktopVisibilityController().onLauncherStateChanged(toState);
+        if (mContainer.getDesktopVisibilityController() != null) {
+            mContainer.getDesktopVisibilityController().onLauncherStateChanged(toState);
         }
     }
 
@@ -184,11 +191,9 @@
     @Override
     public void setOverviewStateEnabled(boolean enabled) {
         super.setOverviewStateEnabled(enabled);
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "overview state enabled state has changed: "
-                + enabled);
         if (enabled) {
-            LauncherState state = mActivity.getStateManager().getState();
-            boolean hasClearAllButton = (state.getVisibleElements(mActivity)
+            LauncherState state = getStateManager().getState();
+            boolean hasClearAllButton = (state.getVisibleElements(mContainer)
                     & CLEAR_ALL_BUTTON) != 0;
             setDisallowScrollToClearAll(!hasClearAllButton);
         }
@@ -198,31 +203,28 @@
     public boolean onTouchEvent(MotionEvent ev) {
         boolean result = super.onTouchEvent(ev);
         // Do not let touch escape to siblings below this view.
-        return result || mActivity.getStateManager().getState().overviewUi;
+        return result || getStateManager().getState().overviewUi;
     }
 
     @Override
     protected DepthController getDepthController() {
-        return mActivity.getDepthController();
+        return mContainer.getDepthController();
     }
 
     @Override
     public void setModalStateEnabled(int taskId, boolean animate) {
         if (taskId != INVALID_TASK_ID) {
             setSelectedTask(taskId);
-            mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate);
-        } else {
-            if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
-                mActivity.getStateManager().goToState(LauncherState.OVERVIEW, animate);
-                resetModalVisuals();
-            }
+            getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate);
+        } else if (mContainer.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
+            getStateManager().goToState(LauncherState.OVERVIEW, animate);
         }
     }
 
     @Override
     protected void onDismissAnimationEnds() {
         super.onDismissAnimationEnds();
-        if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
+        if (mContainer.isInState(OVERVIEW_SPLIT_SELECT)) {
             // We want to keep the tasks translations in this temporary state
             // after resetting the rest above
             setTaskViewsPrimarySplitTranslation(mTaskViewsPrimarySplitTranslation);
@@ -235,13 +237,13 @@
             @SplitConfigurationOptions.StagePosition int stagePosition,
             StatsLogManager.EventEnum splitEvent) {
         super.initiateSplitSelect(taskView, stagePosition, splitEvent);
-        mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
+        getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
     }
 
     @Override
     public void initiateSplitSelect(SplitSelectSource splitSelectSource) {
         super.initiateSplitSelect(splitSelectSource);
-        mActivity.getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
+        getStateManager().goToState(LauncherState.OVERVIEW_SPLIT_SELECT);
     }
 
     @Override
@@ -249,7 +251,7 @@
         if (FeatureFlags.enableSplitContextually()) {
             return !mSplitSelectStateController.isSplitSelectActive();
         } else {
-            return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+            return !mContainer.isInState(OVERVIEW_SPLIT_SELECT);
         }
     }
 
@@ -258,33 +260,36 @@
             RotationTouchHelper rotationTouchHelper) {
         super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
         DesktopVisibilityController desktopVisibilityController =
-                mActivity.getDesktopVisibilityController();
-        if (desktopVisibilityController != null) {
+                mContainer.getDesktopVisibilityController();
+        if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+            // TODO: b/333533253 - Remove after flag rollout
             desktopVisibilityController.setRecentsGestureStart();
         }
     }
 
     @Override
     public void onGestureAnimationEnd() {
-        DesktopVisibilityController desktopVisibilityController = null;
+        DesktopVisibilityController desktopVisibilityController =
+                mContainer.getDesktopVisibilityController();
         boolean showDesktopApps = false;
         GestureState.GestureEndTarget endTarget = null;
-        if (isDesktopModeSupported()) {
-            desktopVisibilityController = mActivity.getDesktopVisibilityController();
+        if (desktopVisibilityController != null) {
+            desktopVisibilityController = mContainer.getDesktopVisibilityController();
             endTarget = mCurrentGestureEndTarget;
             if (endTarget == GestureState.GestureEndTarget.LAST_TASK
-                    && desktopVisibilityController.areFreeformTasksVisible()) {
+                    && desktopVisibilityController.areDesktopTasksVisible()) {
                 // 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;
             }
         }
         super.onGestureAnimationEnd();
-        if (desktopVisibilityController != null) {
+        if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+            // TODO: b/333533253 - Remove after flag rollout
             desktopVisibilityController.setRecentsGestureEnd(endTarget);
         }
         if (showDesktopApps) {
-            SystemUiProxy.INSTANCE.get(mActivity).showDesktopApps(mActivity.getDisplayId(),
+            SystemUiProxy.INSTANCE.get(mContainer).showDesktopApps(mContainer.getDisplayId(),
                     null /* transition */);
         }
     }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b549058..5188d4a 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -24,6 +24,7 @@
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
@@ -32,6 +33,7 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -89,14 +91,30 @@
     private static final int INDEX_SCROLL_ALPHA = 5;
     private static final int NUM_ALPHAS = 6;
 
+    public @interface ScreenshotButtonHiddenFlags { }
+    public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
+
     public @interface SplitButtonHiddenFlags { }
-    public static final int FLAG_IS_NOT_TABLET = 1 << 0;
+    public static final int FLAG_SMALL_SCREEN_HIDE_SPLIT = 1 << 0;
+    public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
 
     public @interface SplitButtonDisabledFlags { }
-    public static final int FLAG_SINGLE_TASK = 1 << 0;
+    public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
+
+    public @interface AppPairButtonHiddenFlags { }
+    public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
+    public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
+    public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
 
     private MultiValueAlpha mMultiValueAlpha;
+
+    protected LinearLayout mActionButtons;
+    // The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
+    // ImageButton in go launcher (does not share a common class with Button). Take care when
+    // casting this.
+    private View mScreenshotButton;
     private Button mSplitButton;
+    private Button mSaveAppPairButton;
 
     @ActionsHiddenFlags
     private int mHiddenFlags;
@@ -104,11 +122,14 @@
     @ActionsDisabledFlags
     protected int mDisabledFlags;
 
+    @ScreenshotButtonHiddenFlags
+    private int mScreenshotButtonHiddenFlags;
+
     @SplitButtonHiddenFlags
     private int mSplitButtonHiddenFlags;
 
-    @SplitButtonDisabledFlags
-    private int mSplitButtonDisabledFlags;
+    @AppPairButtonHiddenFlags
+    private int mAppPairButtonHiddenFlags;
 
     @Nullable
     protected T mCallbacks;
@@ -132,12 +153,16 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
+        mActionButtons = findViewById(R.id.action_buttons);
+        mMultiValueAlpha = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
         mMultiValueAlpha.setUpdateVisibility(true);
 
-        findViewById(R.id.action_screenshot).setOnClickListener(this);
+        mScreenshotButton = findViewById(R.id.action_screenshot);
+        mScreenshotButton.setOnClickListener(this);
         mSplitButton = findViewById(R.id.action_split);
         mSplitButton.setOnClickListener(this);
+        mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
+        mSaveAppPairButton.setOnClickListener(this);
     }
 
     /**
@@ -159,6 +184,8 @@
             mCallbacks.onScreenshot();
         } else if (id == R.id.action_split) {
             mCallbacks.onSplit();
+        } else if (id == R.id.action_save_app_pair) {
+            mCallbacks.onSaveAppPair();
         }
     }
 
@@ -201,7 +228,59 @@
         }
         boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
         LayoutUtils.setViewEnabled(this, isEnabled);
-        updateSplitButtonEnabledState();
+    }
+
+    /**
+     * Updates a batch of flags to hide and show actions buttons when a grouped task (split screen)
+     * is focused.
+     * @param isGroupedTask True if the focused task is a grouped task.
+     */
+    public void updateForGroupedTask(boolean isGroupedTask) {
+        // Update flags to see if split button should be hidden.
+        updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
+        // Update flags to see if screenshot button should be hidden.
+        updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
+        // Update flags to see if save app pair button should be hidden.
+        updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
+    }
+
+    /**
+     * Updates a batch of flags to hide and show actions buttons for tablet/non tablet case.
+     */
+    private void updateForIsTablet() {
+        assert mDp != null;
+        // Update flags to see if split button should be hidden.
+        updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet);
+        // Update flags to see if save app pair button should be hidden.
+        updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet);
+    }
+
+    /**
+     * Updates flags to hide and show actions buttons for 1p/3p launchers.
+     */
+    public void updateFor3pLauncher(boolean is3pLauncher) {
+        updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
+    }
+
+    /**
+     * Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
+     *
+     * @param flag   The flag to update.
+     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+     */
+    private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
+            boolean enable) {
+        if (mScreenshotButton == null) return;
+        if (enable) {
+            mScreenshotButtonHiddenFlags |= flag;
+        } else {
+            mScreenshotButtonHiddenFlags &= ~flag;
+        }
+        int desiredVisibility = mScreenshotButtonHiddenFlags == 0 ? VISIBLE : GONE;
+        if (mScreenshotButton.getVisibility() != desiredVisibility) {
+            mScreenshotButton.setVisibility(desiredVisibility);
+            mActionButtons.requestLayout();
+        }
     }
 
     /**
@@ -210,31 +289,44 @@
      * @param flag   The flag to update.
      * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
      */
-    public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
+    void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag,
+            boolean enable) {
+        if (mSplitButton == null) return;
         if (enable) {
             mSplitButtonHiddenFlags |= flag;
         } else {
             mSplitButtonHiddenFlags &= ~flag;
         }
-        if (mSplitButton == null) return;
-        boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
-        mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
-        findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
+        int desiredVisibility = mSplitButtonHiddenFlags == 0 ? VISIBLE : GONE;
+        if (mSplitButton.getVisibility() != desiredVisibility) {
+            mSplitButton.setVisibility(desiredVisibility);
+            mActionButtons.requestLayout();
+        }
     }
 
     /**
-     * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
+     * Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
      *
      * @param flag   The flag to update.
-     * @param enable Whether to enable the disable flag: True will cause view to be disabled.
+     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
      */
-    public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
-        if (enable) {
-            mSplitButtonDisabledFlags |= flag;
-        } else {
-            mSplitButtonDisabledFlags &= ~flag;
+    private void updateAppPairButtonHiddenFlags(
+            @AppPairButtonHiddenFlags int flag, boolean enable) {
+        if (!FeatureFlags.enableAppPairs()) {
+            return;
         }
-        updateSplitButtonEnabledState();
+
+        if (mSaveAppPairButton == null) return;
+        if (enable) {
+            mAppPairButtonHiddenFlags |= flag;
+        } else {
+            mAppPairButtonHiddenFlags &= ~flag;
+        }
+        int desiredVisibility = mAppPairButtonHiddenFlags == 0 ? VISIBLE : GONE;
+        if (mSaveAppPairButton.getVisibility() != desiredVisibility) {
+            mSaveAppPairButton.setVisibility(desiredVisibility);
+            mActionButtons.requestLayout();
+        }
     }
 
     public MultiProperty getContentAlpha() {
@@ -261,7 +353,7 @@
      * Returns the visibility of the overview actions buttons.
      */
     public @Visibility int getActionsButtonVisibility() {
-        return findViewById(R.id.action_buttons).getVisibility();
+        return mActionButtons.getVisibility();
     }
 
     /**
@@ -277,8 +369,7 @@
         if (mDp == null) {
             return;
         }
-        LayoutParams actionParams = (LayoutParams) findViewById(
-                R.id.action_buttons).getLayoutParams();
+        LayoutParams actionParams = (LayoutParams) mActionButtons.getLayoutParams();
         actionParams.setMargins(
                 actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
                 actionParams.rightMargin, getBottomMargin());
@@ -305,6 +396,7 @@
         mDp = dp;
         mTaskSize.set(taskSize);
         updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
+        updateForIsTablet();
 
         requestLayout();
 
@@ -312,19 +404,11 @@
                 ? R.drawable.ic_split_horizontal
                 : R.drawable.ic_split_vertical;
         mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
-    }
 
-    /**
-     * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
-     * mDisabledFlags.
-     */
-    private void updateSplitButtonEnabledState() {
-        if (mSplitButton == null) {
-            return;
-        }
-        boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
-        boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
-        mSplitButton.setEnabled(shouldBeEnabled);
+        int appPairIconRes = dp.isLeftRightSplit
+                ? R.drawable.ic_save_app_pair_left_right
+                : R.drawable.ic_save_app_pair_up_down;
+        mSaveAppPairButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
+                appPairIconRes, 0, 0, 0);
     }
-
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 87cee63..ae6f703 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -61,9 +61,6 @@
 import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_TAB;
 import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP;
 import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -81,7 +78,6 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.Intent;
@@ -90,7 +86,6 @@
 import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -98,7 +93,6 @@
 import android.graphics.RectF;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -133,7 +127,7 @@
 import androidx.annotation.UiThread;
 import androidx.core.graphics.ColorUtils;
 
-import com.android.launcher3.BaseActivity;
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
@@ -149,15 +143,15 @@
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.BaseState;
-import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.OverScroll;
-import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -167,10 +161,12 @@
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.TranslateEdgeEffect;
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewPool;
-import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.BaseContainerInterface;
+import com.android.quickstep.DesktopModeStatus;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.RecentsAnimationController;
@@ -188,6 +184,7 @@
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.TopTaskTracker;
 import com.android.quickstep.ViewUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActiveGestureErrorDetector;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AnimUtils;
@@ -215,7 +212,7 @@
 import com.android.systemui.shared.system.PackageManagerWrapper;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.pip.IPipAnimationListener;
+import com.android.wm.shell.common.pip.IPipAnimationListener;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -229,9 +226,11 @@
 
 /**
  * A list of recent tasks.
+ * @param <CONTAINER_TYPE> : the container that should host recents view
+ * @param <STATE_TYPE> : the type of base state that will be used
  */
-@TargetApi(Build.VERSION_CODES.R)
-public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
+
+public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewContainer,
         STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
         TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
         TaskVisualsChangeListener {
@@ -444,8 +443,10 @@
 
     private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
 
+    private static final float FOREGROUND_SCRIM_TINT = 0.32f;
+
     protected final RecentsOrientedState mOrientationState;
-    protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
+    protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
     @Nullable
     protected RecentsAnimationController mRecentsAnimationController;
     @Nullable
@@ -461,10 +462,10 @@
 
     @Nullable
     protected RemoteTargetHandle[] mRemoteTargetHandles;
+    protected final Rect mLastComputedCarouselTaskSize = new Rect();
     protected final Rect mLastComputedTaskSize = new Rect();
     protected final Rect mLastComputedGridSize = new Rect();
     protected final Rect mLastComputedGridTaskSize = new Rect();
-    protected final Rect mLastComputedDesktopTaskSize = new Rect();
     private TaskView mSelectedTask = null;
     // How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
     @Nullable
@@ -482,7 +483,7 @@
     // The threshold at which we update the SystemUI flags when animating from the task into the app
     public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
 
-    protected final ACTIVITY_TYPE mActivity;
+    protected final CONTAINER_TYPE mContainer;
     private final float mFastFlingVelocity;
     private final int mScrollHapticMinGapMillis;
     private final RecentsModel mModel;
@@ -492,9 +493,10 @@
     private final Rect mClearAllButtonDeadZoneRect = new Rect();
     private final Rect mTaskViewDeadZoneRect = new Rect();
     /**
-     * Reflects if Recents is currently in the middle of a gesture
+     * Reflects if Recents is currently in the middle of a gesture, and if so, which tasks are
+     * running. If a gesture is not in progress, this will be null.
      */
-    private boolean mGestureActive;
+    private @Nullable Task[] mActiveGestureRunningTasks;
 
     // Keeps track of the previously known visible tasks for purposes of loading/unloading task data
     private final SparseBooleanArray mHasVisibleTaskData = new SparseBooleanArray();
@@ -544,6 +546,9 @@
     private int mOverScrollShift = 0;
     private long mScrollLastHapticTimestamp;
 
+    private int mKeyboardTaskFocusSnapAnimationDuration;
+    private int mKeyboardTaskFocusIndex = INVALID_PAGE;
+
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
      */
@@ -586,8 +591,7 @@
                 return;
             }
             Task.TaskKey taskKey = taskView.getTask().key;
-            UI_HELPER_EXECUTOR.execute(new HandlerRunnable<>(
-                    UI_HELPER_EXECUTOR.getHandler(),
+            UI_HELPER_EXECUTOR.execute(new CancellableTask<>(
                     () -> PackageManagerWrapper.getInstance()
                             .getActivityInfo(taskKey.getComponent(), taskKey.userId) == null,
                     MAIN_EXECUTOR,
@@ -719,6 +723,7 @@
     private int mSplitHiddenTaskViewIndex = -1;
     @Nullable
     private FloatingTaskView mSecondFloatingTaskView;
+    private View mSplitDividerPlaceholderView;
 
     /**
      * The task to be removed and immediately re-added. Should not be added to task pool.
@@ -758,19 +763,22 @@
     private RunnableList mSideTaskLaunchCallback;
     @Nullable
     private TaskLaunchListener mTaskLaunchListener;
+    @Nullable
+    private Runnable mOnTaskLaunchCancelledRunnable;
+
 
     // keeps track of the state of the filter for tasks in recents view
     private final RecentsFilterState mFilterState = new RecentsFilterState();
 
     public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            BaseActivityInterface sizeStrategy) {
+            BaseContainerInterface sizeStrategy) {
         super(context, attrs, defStyleAttr);
         setEnableFreeScroll(true);
         mSizeStrategy = sizeStrategy;
-        mActivity = BaseActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
         mOrientationState = new RecentsOrientedState(
                 context, mSizeStrategy, this::animateRecentsRotationInPlace);
-        final int rotation = mActivity.getDisplay().getRotation();
+        final int rotation = mContainer.getDisplay().getRotation();
         mOrientationState.setRecentsRotation(rotation);
 
         mScrollHapticMinGapMillis = getResources()
@@ -790,7 +798,8 @@
         mDesktopTaskViewPool = new ViewPool<>(context, this, R.layout.task_desktop,
                 5 /* max size */, 1 /* initial size */);
 
-        mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
+        setOrientationHandler(mOrientationState.getOrientationHandler());
+        mIsRtl = getPagedOrientationHandler().getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
         mSplitPlaceholderSize = getResources().getDimensionPixelSize(
                 R.dimen.split_placeholder_size);
@@ -814,7 +823,6 @@
                 .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
         setWillNotDraw(false);
         updateEmptyMessage();
-        mOrientationHandler = mOrientationState.getOrientationHandler();
 
         mTaskOverlayFactory = Overrides.getObject(
                 TaskOverlayFactory.class,
@@ -822,7 +830,7 @@
                 R.string.task_overlay_factory_class);
 
         // Initialize quickstep specific cache params here, as this is constructed only once
-        mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
+        mContainer.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
 
         mTintingColor = getForegroundScrimDimColor(context);
 
@@ -830,9 +838,9 @@
         if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
             // invalidate the current list of tasks if filter changes with a fading in/out animation
             mFilterState.setOnFilterUpdatedListener(() -> {
-                Animator animatorFade = mActivity.getStateManager().createStateElementAnimation(
+                Animator animatorFade = getStateManager().createStateElementAnimation(
                         RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 1f, 0f);
-                Animator animatorAppear = mActivity.getStateManager().createStateElementAnimation(
+                Animator animatorAppear = getStateManager().createStateElementAnimation(
                         RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM, 0f, 1f);
                 animatorFade.addListener(new AnimatorListenerAdapter() {
                     @Override
@@ -920,9 +928,9 @@
         if (mAllowOverScroll && (!mEdgeGlowRight.isFinished() || !mEdgeGlowLeft.isFinished())) {
             final int restoreCount = canvas.save();
 
-            int primarySize = mOrientationHandler.getPrimaryValue(getWidth(), getHeight());
+            int primarySize = getPagedOrientationHandler().getPrimaryValue(getWidth(), getHeight());
             int scroll = OverScroll.dampedScroll(getUndampedOverScrollShift(), primarySize);
-            mOrientationHandler.setPrimary(canvas, CANVAS_TRANSLATE, scroll);
+            getPagedOrientationHandler().setPrimary(canvas, CANVAS_TRANSLATE, scroll);
 
             if (mOverScrollShift != scroll) {
                 mOverScrollShift = scroll;
@@ -946,8 +954,8 @@
     private float getUndampedOverScrollShift() {
         final int width = getWidth();
         final int height = getHeight();
-        int primarySize = mOrientationHandler.getPrimaryValue(width, height);
-        int secondarySize = mOrientationHandler.getSecondaryValue(width, height);
+        int primarySize = getPagedOrientationHandler().getPrimaryValue(width, height);
+        int secondarySize = getPagedOrientationHandler().getSecondaryValue(width, height);
 
         float effectiveShift = 0;
         if (!mEdgeGlowLeft.isFinished()) {
@@ -1057,6 +1065,8 @@
             @Nullable DesktopRecentsTransitionController desktopRecentsTransitionController) {
         mActionsView = actionsView;
         mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
+        // Update flags for 1p/3p launchers
+        mActionsView.updateFor3pLauncher(!supportsAppPairs());
         mSplitSelectStateController = splitController;
         mDesktopRecentsTransitionController = desktopRecentsTransitionController;
     }
@@ -1082,13 +1092,13 @@
         super.onAttachedToWindow();
         updateTaskStackListenerState();
         mModel.getThumbnailCache().getHighResLoadingState().addCallback(this);
-        mActivity.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
+        mContainer.addMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
         TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
         mSyncTransactionApplier = new SurfaceTransactionApplier(this);
         runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
                 .setSyncTransactionApplier(mSyncTransactionApplier));
         RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
-        mIPipAnimationListener.setActivityAndRecentsView(mActivity, this);
+        mIPipAnimationListener.setActivityAndRecentsView(mContainer, this);
         SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(
                 mIPipAnimationListener);
         mOrientationState.initListeners();
@@ -1103,7 +1113,7 @@
         super.onDetachedFromWindow();
         updateTaskStackListenerState();
         mModel.getThumbnailCache().getHighResLoadingState().removeCallback(this);
-        mActivity.removeMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
+        mContainer.removeMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
         TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
         mSyncTransactionApplier = null;
         runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
@@ -1194,6 +1204,21 @@
         }
     }
 
+    /**
+     * This is a one-time callback when touching in live tile mode. It's reset to null right
+     * after it's called.
+     */
+    public void setTaskLaunchCancelledRunnable(Runnable onTaskLaunchCancelledRunnable) {
+        mOnTaskLaunchCancelledRunnable = onTaskLaunchCancelledRunnable;
+    }
+
+    public void onTaskLaunchedInLiveTileModeCancelled() {
+        if (mOnTaskLaunchCancelledRunnable != null) {
+            mOnTaskLaunchCancelledRunnable.run();
+            mOnTaskLaunchCancelledRunnable = null;
+        }
+    }
+
     private void executeSideTaskLaunchCallback() {
         if (mSideTaskLaunchCallback != null) {
             mSideTaskLaunchCallback.executeAllAndDestroy();
@@ -1228,20 +1253,27 @@
         if (taskView == null || !isTaskViewVisible(taskView)) {
             // TODO: Refine this animation.
             SurfaceTransactionApplier surfaceApplier =
-                    new SurfaceTransactionApplier(mActivity.getDragLayer());
+                    new SurfaceTransactionApplier(mContainer.getDragLayer());
             ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
             appAnimator.setDuration(RECENTS_LAUNCH_DURATION);
             appAnimator.setInterpolator(ACCELERATE_DECELERATE);
+            final Matrix matrix = new Matrix();
             appAnimator.addUpdateListener(valueAnimator -> {
                 float percent = valueAnimator.getAnimatedFraction();
                 SurfaceTransaction transaction = new SurfaceTransaction();
-                Matrix matrix = new Matrix();
-                matrix.postScale(percent, percent);
-                matrix.postTranslate(mActivity.getDeviceProfile().widthPx * (1 - percent) / 2,
-                        mActivity.getDeviceProfile().heightPx * (1 - percent) / 2);
-                transaction.forSurface(apps[apps.length - 1].leash)
-                        .setAlpha(percent)
-                        .setMatrix(matrix);
+                for (int i = apps.length - 1; i >= 0; --i) {
+                    RemoteAnimationTarget app = apps[i];
+
+                    float dx = mContainer.getDeviceProfile().widthPx * (1 - percent) / 2
+                            + app.screenSpaceBounds.left * percent;
+                    float dy = mContainer.getDeviceProfile().heightPx * (1 - percent) / 2
+                            + app.screenSpaceBounds.top * percent;
+                    matrix.setScale(percent, percent);
+                    matrix.postTranslate(dx, dy);
+                    transaction.forSurface(app.leash)
+                            .setAlpha(percent)
+                            .setMatrix(matrix);
+                }
                 surfaceApplier.scheduleApply(transaction);
             });
             appAnimator.addListener(new AnimatorListenerAdapter() {
@@ -1251,6 +1283,8 @@
                     final SurfaceTransaction showTransaction = new SurfaceTransaction();
                     for (int i = apps.length - 1; i >= 0; --i) {
                         showTransaction.getTransaction().show(apps[i].leash);
+                        showTransaction.forSurface(apps[i].leash).setLayer(
+                                Integer.MAX_VALUE - 1000 + apps[i].prefixOrderIndex);
                     }
                     surfaceApplier.scheduleApply(showTransaction);
                 }
@@ -1264,7 +1298,7 @@
             });
         } else {
             TaskViewUtils.composeRecentsLaunchAnimator(anim, taskView, apps, wallpaper, nonApps,
-                    true /* launcherClosing */, mActivity.getStateManager(), this,
+                    true /* launcherClosing */, getStateManager(), this,
                     getDepthController());
         }
         anim.start();
@@ -1272,8 +1306,8 @@
 
     public boolean isTaskViewVisible(TaskView tv) {
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int screenEnd = screenStart + getPagedOrientationHandler().getMeasuredSize(this);
             return isTaskViewWithinBounds(tv, screenStart, screenEnd);
         } else {
             // For now, just check if it's the active task or an adjacent task
@@ -1283,8 +1317,8 @@
 
     public boolean isTaskViewFullyVisible(TaskView tv) {
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int screenEnd = screenStart + getPagedOrientationHandler().getMeasuredSize(this);
             return isTaskViewFullyWithinBounds(tv, screenStart, screenEnd);
         } else {
             // For now, just check if it's the active task
@@ -1309,9 +1343,9 @@
 
     private int getSnapToLastTaskScrollDiff() {
         // Snap to a position where ClearAll is just invisible.
-        int screenStart = mOrientationHandler.getPrimaryScroll(this);
+        int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
         int clearAllScroll = getScrollForPage(indexOfChild(mClearAllButton));
-        int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
+        int clearAllWidth = getPagedOrientationHandler().getPrimarySize(mClearAllButton);
         int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
         return screenStart - lastTaskScroll;
     }
@@ -1322,20 +1356,20 @@
     }
 
     private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
-        int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsGrid());
-        int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                showAsFullscreen()));
+        int taskStart = getPagedOrientationHandler().getChildStart(tv)
+                + (int) tv.getOffsetAdjustment(showAsGrid());
+        int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(tv)
+                * tv.getSizeAdjustment(showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
         return (taskStart >= start && taskStart <= end) || (taskEnd >= start
                 && taskEnd <= end);
     }
 
     private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
-        int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsGrid());
-        int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                showAsFullscreen()));
+        int taskStart = getPagedOrientationHandler().getChildStart(tv)
+                + (int) tv.getOffsetAdjustment(showAsGrid());
+        int taskSize = (int) (getPagedOrientationHandler().getMeasuredSize(tv)
+                * tv.getSizeAdjustment(showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
         return taskStart >= start && taskEnd <= end;
     }
@@ -1424,6 +1458,7 @@
             TaskView taskView = requireTaskViewAt(i);
             taskView.setBorderEnabled(enabled);
         }
+        mClearAllButton.setBorderEnabled(enabled);
     }
 
     /**
@@ -1440,12 +1475,11 @@
     @Override
     protected void onPageBeginTransition() {
         super.onPageBeginTransition();
-        if (!mActivity.getDeviceProfile().isTablet) {
+        if (!mContainer.getDeviceProfile().isTablet) {
             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
         }
         if (mOverviewStateEnabled) { // only when in overview
-            InteractionJankMonitorWrapper.begin(/* view= */ this,
-                    InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING);
+            InteractionJankMonitorWrapper.begin(/* view= */ this, Cuj.CUJ_RECENTS_SCROLLING);
         }
     }
 
@@ -1454,18 +1488,18 @@
         super.onPageEndTransition();
         ActiveGestureLog.INSTANCE.addLog(
                 "onPageEndTransition: current page index updated", getNextPage());
-        if (isClearAllHidden() && !mActivity.getDeviceProfile().isTablet) {
+        if (isClearAllHidden() && !mContainer.getDeviceProfile().isTablet) {
             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, false);
         }
         if (getNextPage() > 0) {
             setSwipeDownShouldLaunchApp(true);
         }
-        InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING);
+        InteractionJankMonitorWrapper.end(Cuj.CUJ_RECENTS_SCROLLING);
     }
 
     @Override
     protected boolean isSignificantMove(float absoluteDelta, int pageOrientedSize) {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         if (!deviceProfile.isTablet) {
             return super.isSignificantMove(absoluteDelta, pageOrientedSize);
         }
@@ -1475,6 +1509,15 @@
     }
 
     @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        boolean intercept = super.onInterceptTouchEvent(ev);
+        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            Log.d("b/318590728", "onInterceptTouchEvent: " + ev);
+        }
+        return intercept;
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent ev) {
         super.onTouchEvent(ev);
 
@@ -1614,7 +1657,7 @@
      * required to move the running task in grid.
      */
     public void moveRunningTaskToFront() {
-        if (!mActivity.getDeviceProfile().isTablet) {
+        if (!mContainer.getDeviceProfile().isTablet) {
             return;
         }
 
@@ -1631,7 +1674,7 @@
             return;
         }
 
-        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
         int currentPageScroll = getScrollForPage(mCurrentPage);
         mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
 
@@ -1639,15 +1682,8 @@
         removeView(runningTaskView);
         mMovingTaskView = null;
         runningTaskView.resetPersistentViewTransforms();
-        int frontTaskIndex = 0;
-        if (isDesktopModeSupported() && mDesktopTaskView != null
-                && !runningTaskView.isDesktopTask()) {
-            // If desktop mode is enabled, desktop task view is pinned at first position if present.
-            // Move running task to position 1.
-            frontTaskIndex = 1;
-        }
-        addView(runningTaskView, frontTaskIndex);
-        setCurrentPage(frontTaskIndex);
+        addView(runningTaskView, 0);
+        setCurrentPage(0);
 
         updateTaskSize();
     }
@@ -1707,6 +1743,7 @@
         // Removing views sets the currentPage to 0, so we save this and restore it after
         // the new set of views are added
         int previousCurrentPage = mCurrentPage;
+        int previousFocusedPage = indexOfChild(getFocusedChild());
         removeAllViews();
 
         // If we are entering Overview as a result of initiating a split from somewhere else
@@ -1723,7 +1760,6 @@
 
         // Clear out desktop view if it is set
         mDesktopTaskView = null;
-        DesktopTask desktopTask = null;
 
         // 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.
@@ -1732,12 +1768,6 @@
             boolean isRemovalNeeded = stagedTaskIdToBeRemovedFromGrid != INVALID_TASK_ID
                     && groupTask.containsTask(stagedTaskIdToBeRemovedFromGrid);
 
-            if (groupTask instanceof DesktopTask) {
-                desktopTask = (DesktopTask) groupTask;
-                // Desktop task will be added separately in the end
-                continue;
-            }
-
             TaskView taskView;
             if (isRemovalNeeded && groupTask.hasMultipleTasks()) {
                 // If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
@@ -1768,6 +1798,10 @@
 
                 ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
                         groupTask.mSplitBounds);
+            } else if (taskView instanceof DesktopTaskView) {
+                ((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks,
+                        mOrientationState);
+                mDesktopTaskView = (DesktopTaskView) taskView;
             } else {
                 taskView.bind(groupTask.task1, mOrientationState);
             }
@@ -1780,19 +1814,6 @@
 
         if (!taskGroups.isEmpty()) {
             addView(mClearAllButton);
-            if (isDesktopModeSupported()) {
-                // Check if we have apps on the desktop
-                if (desktopTask != null && !desktopTask.tasks.isEmpty()) {
-                    // If we are actively choosing apps for split, skip the desktop tile
-                    if (!getSplitSelectController().isSplitSelectActive()) {
-                        mDesktopTaskView = (DesktopTaskView) getTaskViewFromPool(
-                                TaskView.Type.DESKTOP);
-                        // Always add a desktop task to the first position
-                        addView(mDesktopTaskView, 0);
-                        mDesktopTaskView.bind(desktopTask.tasks, mOrientationState);
-                    }
-                }
-            }
         }
 
         // Keep same previous focused task
@@ -1800,19 +1821,11 @@
         // If the list changed, maybe the focused task doesn't exist anymore
         if (newFocusedTaskView == null && getTaskViewCount() > 0) {
             newFocusedTaskView = getTaskViewAt(0);
-            // Check if the first task is the desktop.
-            // If first task is desktop, try to find another task to set as the focused task
-            if (newFocusedTaskView != null && newFocusedTaskView.isDesktopTask()
-                    && getTaskViewCount() > 1) {
-                newFocusedTaskView = getTaskViewAt(1);
-            }
         }
         mFocusedTaskViewId = newFocusedTaskView != null && !enableGridOnlyOverview()
                 ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
         updateTaskSize();
-        if (newFocusedTaskView != null) {
-            newFocusedTaskView.setOrientationState(mOrientationState);
-        }
+        updateChildTaskOrientations();
 
         TaskView newRunningTaskView = null;
         if (hasAnyValidTaskIds(runningTaskId)) {
@@ -1822,7 +1835,15 @@
             if (newRunningTaskView != null) {
                 mRunningTaskViewId = newRunningTaskView.getTaskViewId();
             } else {
-                mRunningTaskViewId = INVALID_TASK_ID;
+                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);
+                } else {
+                    mRunningTaskViewId = INVALID_TASK_ID;
+                }
             }
         }
 
@@ -1836,17 +1857,14 @@
                     targetPage = indexOfChild(currentTaskView);
                 }
             }
+        } else if (previousFocusedPage != INVALID_PAGE) {
+            targetPage = previousFocusedPage;
         } else {
             // Set the current page to the running task, but not if settling on new task.
             if (hasAnyValidTaskIds(runningTaskId)) {
                 targetPage = indexOfChild(newRunningTaskView);
             } else if (getTaskViewCount() > 0) {
-                TaskView taskView = requireTaskViewAt(0);
-                // If first task id desktop, try to find another task to set the target page
-                if (taskView.isDesktopTask() && getTaskViewCount() > 1) {
-                    taskView = requireTaskViewAt(1);
-                }
-                targetPage = indexOfChild(taskView);
+                targetPage = indexOfChild(requireTaskViewAt(0));
             }
         }
         if (targetPage != -1 && mCurrentPage != targetPage) {
@@ -1888,10 +1906,17 @@
     }
 
     private void removeTasksViewsAndClearAllButton() {
+        // This handles an edge case where applyLoadPlan happens during a gesture when the
+        // only Task is one with excludeFromRecents, in which case we should not remove it.
+        final int stubRunningTaskIndex = isGestureActive() ? getRunningTaskIndex() : -1;
+
         for (int i = getTaskViewCount() - 1; i >= 0; i--) {
+            if (i == stubRunningTaskIndex) {
+                continue;
+            }
             removeView(requireTaskViewAt(i));
         }
-        if (indexOfChild(mClearAllButton) != -1) {
+        if (getTaskViewCount() == 0 && indexOfChild(mClearAllButton) != -1) {
             removeView(mClearAllButton);
         }
     }
@@ -2000,9 +2025,9 @@
         mInsets.set(insets);
 
         // Update DeviceProfile dependant state.
-        DeviceProfile dp = mActivity.getDeviceProfile();
+        DeviceProfile dp = mContainer.getDeviceProfile();
         setOverviewGridEnabled(
-                mActivity.getStateManager().getState().displayOverviewTasksAsGrid(dp));
+                getStateManager().getState().displayOverviewTasksAsGrid(dp));
         if (enableGridOnlyOverview()) {
             mActionsView.updateHiddenFlags(HIDDEN_ACTIONS_IN_MENU, dp.isTablet);
         }
@@ -2024,22 +2049,22 @@
 
     private void updateOrientationHandler(boolean forceRecreateDragLayerControllers) {
         // Handle orientation changes.
-        PagedOrientationHandler oldOrientationHandler = mOrientationHandler;
-        mOrientationHandler = mOrientationState.getOrientationHandler();
+        RecentsPagedOrientationHandler oldOrientationHandler = getPagedOrientationHandler();
+        setOrientationHandler(mOrientationState.getOrientationHandler());
 
-        mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
+        mIsRtl = getPagedOrientationHandler().getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl
                 ? View.LAYOUT_DIRECTION_RTL
                 : View.LAYOUT_DIRECTION_LTR);
         mClearAllButton.setLayoutDirection(mIsRtl
                 ? View.LAYOUT_DIRECTION_LTR
                 : View.LAYOUT_DIRECTION_RTL);
-        mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
+        mClearAllButton.setRotation(getPagedOrientationHandler().getDegreesRotated());
 
         if (forceRecreateDragLayerControllers
-                || !mOrientationHandler.equals(oldOrientationHandler)) {
+                || !getPagedOrientationHandler().equals(oldOrientationHandler)) {
             // Changed orientations, update controllers so they intercept accordingly.
-            mActivity.getDragLayer().recreateControllers();
+            mContainer.getDragLayer().recreateControllers();
             onOrientationChanged();
             resetTaskVisuals();
         }
@@ -2071,23 +2096,22 @@
 
     // Update task size and padding that are dependent on DeviceProfile and insets.
     private void updateSizeAndPadding() {
-        DeviceProfile dp = mActivity.getDeviceProfile();
-        getTaskSize(mTempRect);
-        mTaskWidth = mTempRect.width();
-        mTaskHeight = mTempRect.height();
+        DeviceProfile dp = mContainer.getDeviceProfile();
+        getTaskSize(mLastComputedTaskSize);
+        mTaskWidth = mLastComputedTaskSize.width();
+        mTaskHeight = mLastComputedTaskSize.height();
+        setPadding(mLastComputedTaskSize.left - mInsets.left,
+                mLastComputedTaskSize.top - dp.overviewTaskThumbnailTopMarginPx - mInsets.top,
+                dp.widthPx - mInsets.right - mLastComputedTaskSize.right,
+                dp.heightPx - mInsets.bottom - mLastComputedTaskSize.bottom);
 
-        mTempRect.top -= dp.overviewTaskThumbnailTopMarginPx;
-        setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
-                dp.widthPx - mInsets.right - mTempRect.right,
-                dp.heightPx - mInsets.bottom - mTempRect.bottom);
+        mSizeStrategy.calculateGridSize(dp, mContainer, mLastComputedGridSize);
+        mSizeStrategy.calculateGridTaskSize(mContainer, dp, mLastComputedGridTaskSize,
+                getPagedOrientationHandler());
 
-        mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(), mActivity,
-                mLastComputedGridSize);
-        mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
-                mLastComputedGridTaskSize, mOrientationHandler);
-        if (isDesktopModeSupported()) {
-            mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
-                    mLastComputedDesktopTaskSize);
+        if (enableGridOnlyOverview()) {
+            mSizeStrategy.calculateCarouselTaskSize(mContainer, dp, mLastComputedCarouselTaskSize,
+                    getPagedOrientationHandler());
         }
 
         mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
@@ -2097,6 +2121,7 @@
 
         // Force TaskView to update size from thumbnail
         updateTaskSize();
+        updatePivots();
     }
 
     /**
@@ -2118,9 +2143,12 @@
         }
 
         float accumulatedTranslationX = 0;
-        float translateXToMiddle = enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
-                ? mActivity.getDeviceProfile().widthPx / 2 - mLastComputedGridTaskSize.centerX()
-                : 0;
+        float translateXToMiddle = 0;
+        if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet) {
+            translateXToMiddle = mIsRtl
+                    ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
+                    : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
+        }
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
             taskView.updateTaskSize();
@@ -2138,9 +2166,8 @@
     }
 
     public void getTaskSize(Rect outRect) {
-        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
-                mOrientationHandler);
-        mLastComputedTaskSize.set(outRect);
+        mSizeStrategy.calculateTaskSize(mContainer, mContainer.getDeviceProfile(), outRect,
+                getPagedOrientationHandler());
     }
 
     /**
@@ -2162,7 +2189,7 @@
 
     private Rect getTaskBounds(TaskView taskView) {
         int selectedPage = indexOfChild(taskView);
-        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
         int selectedPageScroll = getScrollForPage(selectedPage);
         boolean isTopRow = taskView != null && mTopRowIdSet.contains(taskView.getTaskViewId());
         Rect outRect = new Rect(mLastComputedTaskSize);
@@ -2182,15 +2209,14 @@
         return mLastComputedGridTaskSize;
     }
 
-    /** Gets the last computed desktop task size */
-    public Rect getLastComputedDesktopTaskSize() {
-        return mLastComputedDesktopTaskSize;
+    public Rect getLastComputedCarouselTaskSize() {
+        return mLastComputedCarouselTaskSize;
     }
 
     /** Gets the task size for modal state. */
     public void getModalTaskSize(Rect outRect) {
-        mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
-                mOrientationHandler);
+        mSizeStrategy.calculateModalTaskSize(mContainer, mContainer.getDeviceProfile(), outRect,
+                getPagedOrientationHandler());
     }
 
     @Override
@@ -2246,7 +2272,7 @@
         if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
             return;
         }
-        int scroll = mOrientationHandler.getPrimaryScroll(this);
+        int scroll = getPagedOrientationHandler().getPrimaryScroll(this);
         mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
 
         // Clear all button alpha was set by the previous line.
@@ -2255,7 +2281,7 @@
 
     @Override
     protected int getDestinationPage(int scaledScroll) {
-        if (!mActivity.getDeviceProfile().isTablet) {
+        if (!mContainer.getDeviceProfile().isTablet) {
             return super.getDestinationPage(scaledScroll);
         }
         if (!isPageScrollsInitialized()) {
@@ -2296,8 +2322,8 @@
         int visibleStart = 0;
         int visibleEnd = 0;
         if (showAsGrid()) {
-            int screenStart = mOrientationHandler.getPrimaryScroll(this);
-            int pageOrientedSize = mOrientationHandler.getMeasuredSize(this);
+            int screenStart = getPagedOrientationHandler().getPrimaryScroll(this);
+            int pageOrientedSize = getPagedOrientationHandler().getMeasuredSize(this);
             // For GRID_ONLY_OVERVIEW, use +/- 1 task column as visible area for preloading
             // adjacent thumbnails, otherwise use +/-50% screen width
             int extraWidth = enableGridOnlyOverview() ? getLastComputedTaskSize().width()
@@ -2345,7 +2371,7 @@
                         // Ignore thumbnail update if it's current running task during the gesture
                         // We snapshot at end of gesture, it will update then
                         int changes = dataChanges;
-                        if (taskView == getRunningTaskView() && mGestureActive) {
+                        if (taskView == getRunningTaskView() && isGestureActive()) {
                             changes &= ~TaskView.FLAG_UPDATE_THUMBNAIL;
                         }
                         taskView.onTaskListVisibilityChanged(true /* visible */, changes);
@@ -2405,7 +2431,7 @@
     }
 
     public void startHome() {
-        startHome(mActivity.isStarted());
+        startHome(mContainer.isStarted());
     }
 
     public void startHome(boolean animated) {
@@ -2418,6 +2444,8 @@
     /** Returns whether user can start home based on state in {@link OverviewCommandHelper}. */
     protected abstract boolean canStartHomeSafely();
 
+    public abstract StateManager<STATE_TYPE> getStateManager();
+
     public void reset() {
         setCurrentTask(-1);
         mCurrentPageScrollDiff = 0;
@@ -2425,19 +2453,21 @@
         mTaskListChangeId = -1;
         mFocusedTaskViewId = -1;
 
-        if (mRecentsAnimationController != null) {
-            if (mEnableDrawingLiveTile) {
-                // We are still drawing the live tile, finish it now to clean up.
+        Log.d(TAG, "reset - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile
+                + ", mRecentsAnimationController: " + mRecentsAnimationController);
+        if (mEnableDrawingLiveTile) {
+            if (mRecentsAnimationController != null) {
+                // We owns mRecentsAnimationController, finish it now to clean up.
                 finishRecentsAnimation(true /* toRecents */, null);
             } else {
-                mRecentsAnimationController = null;
+                // Only clean up target set if we no longer owns mRecentsAnimationController.
+                runActionOnRemoteHandles(remoteTargetHandle ->
+                        remoteTargetHandle.getTransformParams().setTargetSet(null));
             }
+            setEnableDrawingLiveTile(false);
         }
-        setEnableDrawingLiveTile(false);
-        runActionOnRemoteHandles(remoteTargetHandle -> {
-            remoteTargetHandle.getTransformParams().setTargetSet(null);
-            remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
-        });
+        runActionOnRemoteHandles(remoteTargetHandle ->
+                remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
         if (!FeatureFlags.enableSplitContextually()) {
             resetFromSplitSelectionState();
         }
@@ -2555,7 +2585,8 @@
      */
     public void onGestureAnimationStart(
             Task[] runningTasks, RotationTouchHelper rotationTouchHelper) {
-        mGestureActive = true;
+        Log.d(TAG, "onGestureAnimationStart");
+        mActiveGestureRunningTasks = runningTasks;
         // This needs to be called before the other states are set since it can create the task view
         if (mOrientationState.setGestureActive(true)) {
             setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
@@ -2565,13 +2596,17 @@
             updateSizeAndPadding();
         }
 
-        showCurrentTask(runningTasks);
+        showCurrentTask(mActiveGestureRunningTasks);
         setEnableFreeScroll(false);
         setEnableDrawingLiveTile(false);
         setRunningTaskHidden(true);
         setTaskIconScaledDown(true);
     }
 
+    private boolean isGestureActive() {
+        return mActiveGestureRunningTasks != null;
+    }
+
     /**
      * Called only when a swipe-up gesture from an app has completed. Only called after
      * {@link #onGestureAnimationStart} and {@link #onGestureAnimationEnd()}.
@@ -2589,7 +2624,7 @@
         AnimatorSet pa = setRecentsChangedOrientation(true);
         pa.addListener(AnimatorListeners.forSuccessCallback(() -> {
             setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
-            mActivity.getDragLayer().recreateControllers();
+            mContainer.getDragLayer().recreateControllers();
             setRecentsChangedOrientation(false).start();
         }));
         pa.start();
@@ -2618,7 +2653,7 @@
         if (!shouldRotateMenuForFakeRotation) {
             return;
         }
-        TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU);
+        TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mContainer, TYPE_TASK_MENU);
         if (tv != null) {
             // Rotation is supported on phone (details at b/254198019#comment4)
             tv.onRotationChanged();
@@ -2631,6 +2666,7 @@
     public void onPrepareGestureEndAnimation(
             @Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
             TaskViewSimulator[] taskViewSimulators) {
+        Log.d(TAG, "onPrepareGestureEndAnimation - endTarget: " + endTarget);
         mCurrentGestureEndTarget = endTarget;
         boolean isOverviewEndTarget = endTarget == GestureState.GestureEndTarget.RECENTS;
         if (isOverviewEndTarget) {
@@ -2638,7 +2674,7 @@
         }
 
         BaseState<?> endState = mSizeStrategy.stateFromGestureEndTarget(endTarget);
-        if (endState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
+        if (endState.displayOverviewTasksAsGrid(mContainer.getDeviceProfile())) {
             TaskView runningTaskView = getRunningTaskView();
             float runningTaskPrimaryGridTranslation = 0;
             float runningTaskSecondaryGridTranslation = 0;
@@ -2656,6 +2692,9 @@
                     tvs.taskSecondaryTranslation.value = runningTaskSecondaryGridTranslation;
                 } else {
                     animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
+                    animatorSet.play(tvs.carouselScale.animateToValue(1));
+                    animatorSet.play(tvs.carouselPrimaryTranslation.animateToValue(0));
+                    animatorSet.play(tvs.carouselSecondaryTranslation.animateToValue(0));
                     animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
                             runningTaskPrimaryGridTranslation));
                     animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
@@ -2676,13 +2715,14 @@
      * Called when a gesture from an app has finished, and the animation to the target has ended.
      */
     public void onGestureAnimationEnd() {
-        mGestureActive = false;
+        mActiveGestureRunningTasks = null;
         if (mOrientationState.setGestureActive(false)) {
             updateOrientationHandler(/* forceRecreateDragLayerControllers = */ false);
         }
 
         setEnableFreeScroll(true);
         setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS);
+        Log.d(TAG, "onGestureAnimationEnd - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile);
         setRunningTaskHidden(false);
         animateUpTaskIconScale();
         animateActionsViewIn();
@@ -2777,7 +2817,7 @@
     }
 
     private boolean hasDesktopTask(Task[] runningTasks) {
-        if (!isDesktopModeSupported()) {
+        if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
             return false;
         }
         for (Task task : runningTasks) {
@@ -2897,7 +2937,7 @@
             return;
         }
 
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
 
         int topRowWidth = 0;
@@ -2917,13 +2957,11 @@
         int focusedTaskShift = 0;
         int focusedTaskWidthAndSpacing = 0;
         int snappedTaskRowWidth = 0;
-        int snappedPage = getNextPage();
+        int snappedPage = isKeyboardTaskFocusPending() ? mKeyboardTaskFocusIndex : getNextPage();
         TaskView snappedTaskView = getTaskViewAt(snappedPage);
         TaskView homeTaskView = getHomeTaskView();
         TaskView nextFocusedTaskView = null;
 
-        int desktopTaskIndex = Integer.MAX_VALUE;
-
         if (!isTaskDismissal) {
             mTopRowIdSet.clear();
         }
@@ -2950,21 +2988,6 @@
                     // If focused task is snapped, the row width is just task width and spacing.
                     snappedTaskRowWidth = taskWidthAndSpacing;
                 }
-            } else if (taskView.isDesktopTask()) {
-                // Desktop task was not focused. Pin it to the right of focused
-                desktopTaskIndex = i;
-                if (taskView.getVisibility() == View.GONE) {
-                    // Desktop task view is hidden, skip it from grid calculations
-                    continue;
-                }
-                if (!enableGridOnlyOverview()) {
-                    // Only apply x-translation when using legacy overview grid
-                    gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
-                }
-
-                // Center view vertically in case it's from different orientation.
-                taskView.setGridTranslationY((mLastComputedDesktopTaskSize.height() + taskTopMargin
-                        - taskView.getLayoutParams().height) / 2f);
             } else {
                 if (i > focusedTaskIndex) {
                     // For tasks after the focused task, shift by focused task's width and spacing.
@@ -3005,7 +3028,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex || j == desktopTaskIndex) {
+                        if (j == focusedTaskIndex) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3024,7 +3047,7 @@
                     // Move horizontally into empty space.
                     float widthOffset = 0;
                     for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
-                        if (j == focusedTaskIndex || j == desktopTaskIndex) {
+                        if (j == focusedTaskIndex) {
                             continue;
                         }
                         widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3235,10 +3258,10 @@
                 clampToProgress(isOnGridBottomRow(taskView) ? ACCELERATE : FINAL_FRAME, 0, 0.5f));
         FloatProperty<TaskView> secondaryViewTranslate =
                 taskView.getSecondaryDismissTranslationProperty();
-        int secondaryTaskDimension = mOrientationHandler.getSecondaryDimension(taskView);
-        int verticalFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor();
+        int secondaryTaskDimension = getPagedOrientationHandler().getSecondaryDimension(taskView);
+        int verticalFactor = getPagedOrientationHandler().getSecondaryTranslationDirectionFactor();
 
-        ResourceProvider rp = DynamicResource.provider(mActivity);
+        ResourceProvider rp = DynamicResource.provider(mContainer);
         SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_START)
                 .setDampingRatio(rp.getFloat(R.dimen.dismiss_task_trans_y_damping_ratio))
                 .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_y_stiffness));
@@ -3246,11 +3269,12 @@
         anim.add(ObjectAnimator.ofFloat(taskView, secondaryViewTranslate,
                 verticalFactor * secondaryTaskDimension * 2).setDuration(duration), LINEAR, sp);
 
-        if (mEnableDrawingLiveTile && taskView.isRunningTask()) {
+        if (taskView.isRunningTask()) {
             anim.addOnFrameCallback(() -> {
+                if (!mEnableDrawingLiveTile) return;
                 runActionOnRemoteHandles(
                         remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
-                                .taskSecondaryTranslation.value = mOrientationHandler
+                                .taskSecondaryTranslation.value = getPagedOrientationHandler()
                                 .getSecondaryValue(taskView.getTranslationX(),
                                         taskView.getTranslationY()
                                 ));
@@ -3264,11 +3288,11 @@
      * and then animates it into the split position that was desired
      */
     private void createInitialSplitSelectAnimation(PendingAnimation anim) {
-        mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
-                mSplitPlaceholderInset, mActivity.getDeviceProfile(),
+        getPagedOrientationHandler().getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
+                mSplitPlaceholderInset, mContainer.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
         SplitAnimationTimings timings =
-                AnimUtils.getDeviceOverviewToSplitTimings(mActivity.getDeviceProfile().isTablet);
+                AnimUtils.getDeviceOverviewToSplitTimings(mContainer.getDeviceProfile().isTablet);
 
         RectF startingTaskRect = new RectF();
         safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
@@ -3284,7 +3308,7 @@
                     timings.getIconFadeEndOffset()));
         }
 
-        FloatingTaskView firstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
+        FloatingTaskView firstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mContainer,
                 splitAnimInitProps.getOriginalView(),
                 splitAnimInitProps.getOriginalBitmap(),
                 splitAnimInitProps.getIconDrawable(), startingTaskRect);
@@ -3296,13 +3320,13 @@
         // Allow user to click staged app to launch into fullscreen
         firstFloatingTaskView.setOnClickListener(view ->
                 mSplitSelectStateController.getSplitAnimationController().
-                        playAnimPlaceholderToFullscreen(mActivity, view,
+                        playAnimPlaceholderToFullscreen(mContainer, view,
                                 Optional.of(() -> resetFromSplitSelectionState())));
 
         // SplitInstructionsView: animate in
         safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
         SplitInstructionsView splitInstructionsView =
-                SplitInstructionsView.getSplitInstructionsView(mActivity);
+                SplitInstructionsView.getSplitInstructionsView(mContainer);
         splitInstructionsView.setAlpha(0);
         anim.setViewAlpha(splitInstructionsView, 1, clampToProgress(LINEAR,
                 timings.getInstructionsContainerFadeInStartOffset(),
@@ -3313,8 +3337,8 @@
                         timings.getInstructionsUnfoldEndOffset()));
         mSplitSelectStateController.setSplitInstructionsView(splitInstructionsView);
 
-        InteractionJankMonitorWrapper.begin(this,
-                InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
+        InteractionJankMonitorWrapper.begin(this, Cuj.CUJ_SPLIT_SCREEN_ENTER,
+                "First tile selected");
         anim.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
@@ -3330,8 +3354,7 @@
         });
         anim.addEndListener(success -> {
             if (success) {
-                InteractionJankMonitorWrapper.end(
-                        InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+                InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
             } else {
                 // If transition to split select was interrupted, clean up to prevent glitches
                 if (FeatureFlags.enableSplitContextually()) {
@@ -3339,8 +3362,7 @@
                 } else {
                     resetFromSplitSelectionState();
                 }
-                InteractionJankMonitorWrapper.cancel(
-                        InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+                InteractionJankMonitorWrapper.cancel(Cuj.CUJ_SPLIT_SCREEN_ENTER);
             }
 
             updateCurrentTaskActionsVisibility();
@@ -3430,7 +3452,7 @@
         boolean isClearAllHidden = isClearAllHidden();
         boolean snapToLastTask = false;
         boolean isLeftRightSplit =
-                mActivity.getDeviceProfile().isLeftRightSplit && isSplitSelectionActive();
+                mContainer.getDeviceProfile().isLeftRightSplit && isSplitSelectionActive();
         TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
         int currentPageScroll = getScrollForPage(mCurrentPage);
         int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
@@ -3475,7 +3497,7 @@
                     // and adjust accordingly to the new shortTotalCompensation after dismiss.
                     int newClearAllShortTotalWidthTranslation = 0;
                     if (longRowWidth < mLastComputedGridSize.width()) {
-                        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+                        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
                         newClearAllShortTotalWidthTranslation =
                                 (mIsRtl
                                         ? mLastComputedTaskSize.right
@@ -3495,7 +3517,7 @@
                 // beyond that, we'll need to snap to last task instead.
                 TaskView lastTask = getLastGridTaskView();
                 if (lastTask != null) {
-                    int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+                    int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
                     int lastTaskScroll = getScrollForPage(indexOfChild(lastTask));
                     if ((mIsRtl && primaryScroll < lastTaskScroll)
                             || (!mIsRtl && primaryScroll > lastTaskScroll)) {
@@ -3562,7 +3584,7 @@
         }
 
         SplitAnimationTimings splitTimings =
-                AnimUtils.getDeviceOverviewToSplitTimings(mActivity.getDeviceProfile().isTablet);
+                AnimUtils.getDeviceOverviewToSplitTimings(mContainer.getDeviceProfile().isTablet);
 
         int distanceFromDismissedTask = 0;
         for (int i = 0; i < count; i++) {
@@ -3601,7 +3623,7 @@
                 if (scrollDiff != 0) {
                     FloatProperty translationProperty = child instanceof TaskView
                             ? ((TaskView) child).getPrimaryDismissTranslationProperty()
-                            : mOrientationHandler.getPrimaryViewTranslate();
+                            : getPagedOrientationHandler().getPrimaryViewTranslate();
 
                     float additionalDismissDuration =
                             ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
@@ -3637,7 +3659,7 @@
                                     remoteTargetHandle ->
                                             remoteTargetHandle.getTaskViewSimulator()
                                                     .taskPrimaryTranslation.value =
-                                                    mOrientationHandler.getPrimaryValue(
+                                                    getPagedOrientationHandler().getPrimaryValue(
                                                             child.getTranslationX(),
                                                             child.getTranslationY()
                                                     ));
@@ -3713,7 +3735,7 @@
                     if (isStagingFocusedTask) {
                         // Moves less if focused task is not in scroll position.
                         int focusedTaskScroll = getScrollForPage(dismissedIndex);
-                        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+                        int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
                         int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
                         primaryTranslation +=
                                 mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
@@ -3771,7 +3793,7 @@
                             }
                             announceForAccessibility(
                                     getResources().getString(R.string.task_view_closed));
-                            mActivity.getStatsLogManager().logger()
+                            mContainer.getStatsLogManager().logger()
                                     .withItemInfo(dismissedTaskView.getItemInfo())
                                     .log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
                         }
@@ -3841,7 +3863,7 @@
                             }
 
                             if (calculateScrollDiff) {
-                                int primaryScroll = mOrientationHandler.getPrimaryScroll(
+                                int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(
                                         RecentsView.this);
                                 int currentPageScroll = getScrollForPage(mCurrentPage);
                                 mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
@@ -3882,9 +3904,9 @@
                                 TaskView taskView = requireTaskViewAt(highestVisibleTaskIndex);
 
                                 boolean shouldRebalance;
-                                int screenStart = mOrientationHandler.getPrimaryScroll(
+                                int screenStart = getPagedOrientationHandler().getPrimaryScroll(
                                         RecentsView.this);
-                                int taskStart = mOrientationHandler.getChildStart(taskView)
+                                int taskStart = getPagedOrientationHandler().getChildStart(taskView)
                                         + (int) taskView.getOffsetAdjustment(/*gridEnabled=*/ true);
 
                                 // Rebalance only if there is a maximum gap between the task and the
@@ -3893,10 +3915,11 @@
                                 if (mIsRtl) {
                                     shouldRebalance = taskStart <= screenStart + mPageSpacing;
                                 } else {
-                                    int screenEnd =
-                                            screenStart + mOrientationHandler.getMeasuredSize(
-                                                    RecentsView.this);
-                                    int taskSize = (int) (mOrientationHandler.getMeasuredSize(
+                                    int screenEnd = screenStart
+                                            + getPagedOrientationHandler().getMeasuredSize(
+                                            RecentsView.this);
+                                    int taskSize = (int) (
+                                            getPagedOrientationHandler().getMeasuredSize(
                                             taskView) * taskView
                                             .getSizeAdjustment(/*fullscreenEnabled=*/false));
                                     int taskEnd = taskStart + taskSize;
@@ -3936,7 +3959,7 @@
                         // Update various scroll-dependent UI.
                         dispatchScrollChanged();
                         updateActionsViewFocusedScroll();
-                        if (isClearAllHidden() && !mActivity.getDeviceProfile().isTablet) {
+                        if (isClearAllHidden() && !mContainer.getDeviceProfile().isTablet) {
                             mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING,
                                     false);
                         }
@@ -3950,22 +3973,29 @@
     }
 
     /**
-     * Hides all overview actions if current page is for split apps, shows otherwise
-     * If actions are showing, we only show split option if
+     * Hides all overview actions if user is halfway through split selection, shows otherwise.
+     * We only show split option if:
+     * * Focused view is a single app
      * * Device is large screen
-     * * There are at least 2 tasks to invoke split
      */
     private void updateCurrentTaskActionsVisibility() {
         boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
-        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
-        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
-        mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
-                !mActivity.getDeviceProfile().isTablet);
-        mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
-        if (isDesktopModeSupported()) {
-            boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
-            mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
+        // Update flags to see if entire actions bar should be hidden.
+        if (!FeatureFlags.enableAppPairs()) {
+            mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
         }
+        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
+        // Update flags to see if actions bar should show buttons for a single task or a pair of
+        // tasks.
+        mActionsView.updateForGroupedTask(isCurrentSplit);
+
+        boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
+        mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
+    }
+
+    /** Returns if app pairs are supported in this launcher. Overridden in subclasses. */
+    public boolean supportsAppPairs() {
+        return true;
     }
 
     /**
@@ -4079,10 +4109,10 @@
 
     private boolean snapToPageRelative(int delta, boolean cycle,
             @TaskGridNavHelper.TASK_NAV_DIRECTION int direction) {
-        // Ignore grid page snap events while scroll animations are running, otherwise the next
-        // page gets set before the animation finishes and can cause jumps.
+        // Set next page if scroll animation is still running, otherwise cannot snap to the
+        // next page on successive key presses. Setting the current page aborts the scroll.
         if (!mScroller.isFinished()) {
-            return true;
+            setCurrentPage(getNextPage());
         }
         int pageCount = getPageCount();
         if (pageCount == 0) {
@@ -4151,7 +4181,7 @@
     @SuppressWarnings("unused")
     private void dismissAllTasks(View view) {
         runDismissAnimation(createAllTasksDismissAnimation(DISMISS_TASK_DURATION));
-        mActivity.getStatsLogManager().logger().log(LAUNCHER_TASK_CLEAR_ALL);
+        mContainer.getStatsLogManager().logger().log(LAUNCHER_TASK_CLEAR_ALL);
     }
 
     private void dismissCurrentTask() {
@@ -4163,30 +4193,31 @@
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_DOWN) {
-            switch (event.getKeyCode()) {
-                case KeyEvent.KEYCODE_TAB:
-                    return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
-                            DIRECTION_TAB);
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                    return snapToPageRelative(mIsRtl ? -1 : 1, true /* cycle */, DIRECTION_RIGHT);
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                    return snapToPageRelative(mIsRtl ? 1 : -1, true /* cycle */, DIRECTION_LEFT);
-                case KeyEvent.KEYCODE_DPAD_UP:
-                    return snapToPageRelative(1, false /* cycle */, DIRECTION_UP);
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                    return snapToPageRelative(1, false /* cycle */, DIRECTION_DOWN);
-                case KeyEvent.KEYCODE_DEL:
-                case KeyEvent.KEYCODE_FORWARD_DEL:
+        if (isHandlingTouch() || event.getAction() != KeyEvent.ACTION_DOWN) {
+            return super.dispatchKeyEvent(event);
+        }
+        switch (event.getKeyCode()) {
+            case KeyEvent.KEYCODE_TAB:
+                return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
+                        DIRECTION_TAB);
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                return snapToPageRelative(mIsRtl ? -1 : 1, true /* cycle */, DIRECTION_RIGHT);
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                return snapToPageRelative(mIsRtl ? 1 : -1, true /* cycle */, DIRECTION_LEFT);
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return snapToPageRelative(1, false /* cycle */, DIRECTION_UP);
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                return snapToPageRelative(1, false /* cycle */, DIRECTION_DOWN);
+            case KeyEvent.KEYCODE_DEL:
+            case KeyEvent.KEYCODE_FORWARD_DEL:
+                dismissCurrentTask();
+                return true;
+            case KeyEvent.KEYCODE_NUMPAD_DOT:
+                if (event.isAltPressed()) {
+                    // Numpad DEL pressed while holding Alt.
                     dismissCurrentTask();
                     return true;
-                case KeyEvent.KEYCODE_NUMPAD_DOT:
-                    if (event.isAltPressed()) {
-                        // Numpad DEL pressed while holding Alt.
-                        dismissCurrentTask();
-                        return true;
-                    }
-            }
+                }
         }
         return super.dispatchKeyEvent(event);
     }
@@ -4224,10 +4255,12 @@
         for (int i = getTaskViewCount() - 1; i >= 0; i--) {
             TaskView child = requireTaskViewAt(i);
             int[] childTaskIds = child.getTaskIds();
-            if (!mRunningTaskTileHidden ||
-                    (childTaskIds[0] != runningTaskId && childTaskIds[1] != runningTaskId)) {
-                child.setStableAlpha(alpha);
+            if (runningTaskId != INVALID_TASK_ID
+                    && mRunningTaskTileHidden
+                    && (childTaskIds[0] == runningTaskId || childTaskIds[1] == runningTaskId)) {
+                continue;
             }
+            child.setStableAlpha(alpha);
         }
         mClearAllButton.setContentAlpha(mContentAlpha);
         int alphaInt = Math.round(alpha * 255);
@@ -4277,7 +4310,8 @@
      * Updates {@link RecentsOrientedState}'s cached RecentsView rotation.
      */
     public void updateRecentsRotation() {
-        final int rotation = mActivity.getDisplay().getRotation();
+        final int rotation = TraceHelper.allowIpcs(
+                "RecentsView.updateRecentsRotation", () -> mContainer.getDisplay().getRotation());
         mOrientationState.setRecentsRotation(rotation);
     }
 
@@ -4291,8 +4325,8 @@
         return mOrientationState;
     }
 
-    public PagedOrientationHandler getPagedOrientationHandler() {
-        return mOrientationHandler;
+    public RecentsPagedOrientationHandler getPagedOrientationHandler() {
+        return (RecentsPagedOrientationHandler) super.getPagedOrientationHandler();
     }
 
     @Nullable
@@ -4367,9 +4401,6 @@
 
         updateEmptyStateUi(changed);
 
-        // Update the pivots such that when the task is scaled, it fills the full page
-        getTaskSize(mTempRect);
-        updatePivots();
         setTaskModalness(mTaskModalness);
         mLastComputedTaskStartPushOutDistance = null;
         mLastComputedTaskEndPushOutDistance = null;
@@ -4383,21 +4414,25 @@
 
     private void updatePivots() {
         if (mOverviewSelectEnabled) {
-            getModalTaskSize(mTempRect);
-            Rect selectedTaskPosition = getSelectedTaskBounds();
-
-            Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition,
-                    mTempPointF);
+            if (enableGridOnlyOverview()) {
+                getModalTaskSize(mTempRect);
+                Rect selectedTaskPosition = getSelectedTaskBounds();
+                Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition,
+                        mTempPointF);
+            } else {
+                mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom);
+            }
         } else {
-            mTempRect.set(mLastComputedTaskSize);
             // Only update pivot when it is tablet and not in grid yet, so the pivot is correct
             // for non-current tasks when swiping up to overview
-            if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
+            if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet
                     && !mOverviewGridEnabled) {
-                mTempRect.offset(mActivity.getDeviceProfile().widthPx / 2 - mTempRect.centerX(), 0);
+                mTempRect.set(mLastComputedCarouselTaskSize);
+            } else {
+                mTempRect.set(mLastComputedTaskSize);
             }
             getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
-                    mActivity.getDeviceProfile(), mTempPointF);
+                    mContainer.getDeviceProfile(), mTempPointF);
         }
         setPivotX(mTempPointF.x);
         setPivotY(mTempPointF.y);
@@ -4467,7 +4502,7 @@
             View child = getChildAt(i);
             FloatProperty translationPropertyX = child instanceof TaskView
                     ? ((TaskView) child).getPrimaryTaskOffsetTranslationProperty()
-                    : mOrientationHandler.getPrimaryViewTranslate();
+                    : getPagedOrientationHandler().getPrimaryViewTranslate();
             translationPropertyX.set(child, totalTranslationX);
             if (mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
                 runActionOnRemoteHandles(
@@ -4497,7 +4532,7 @@
             TaskView taskView = (TaskView) child;
             outRect.offset(taskView.getPersistentTranslationX(),
                     taskView.getPersistentTranslationY());
-            outRect.top += mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+            outRect.top += mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
 
             mTempMatrix.reset();
             float persistentScale = taskView.getPersistentScale();
@@ -4505,8 +4540,8 @@
                     mIsRtl ? outRect.right : outRect.left, outRect.top);
             mTempMatrix.mapRect(outRect);
         }
-        outRect.offset(mOrientationHandler.getPrimaryValue(-midPointScroll, 0),
-                mOrientationHandler.getSecondaryValue(-midPointScroll, 0));
+        outRect.offset(getPagedOrientationHandler().getPrimaryValue(-midPointScroll, 0),
+                getPagedOrientationHandler().getSecondaryValue(-midPointScroll, 0));
     }
 
     /**
@@ -4531,14 +4566,15 @@
             // to reach offscreen. Offset the task position to the task's starting point, and offset
             // by current page's scroll diff.
             int midpointScroll = getScrollForPage(midpointIndex)
-                    + mOrientationHandler.getPrimaryScroll(this) - getScrollForPage(mCurrentPage);
+                    + getPagedOrientationHandler().getPrimaryScroll(this)
+                    - getScrollForPage(mCurrentPage);
 
             getPersistentChildPosition(midpointIndex, midpointScroll, taskPosition);
-            float midpointStart = mOrientationHandler.getStart(taskPosition);
+            float midpointStart = getPagedOrientationHandler().getStart(taskPosition);
 
             getPersistentChildPosition(childIndex, midpointScroll, taskPosition);
             // Assume child does not overlap with midPointChild.
-            isStartShift = mOrientationHandler.getStart(taskPosition) < midpointStart;
+            isStartShift = getPagedOrientationHandler().getStart(taskPosition) < midpointStart;
         } else {
             // Position the task at scroll position.
             getPersistentChildPosition(childIndex, getScrollForPage(childIndex), taskPosition);
@@ -4552,27 +4588,29 @@
         // desired position, and adjust the computed distance accordingly.
         float distanceToOffscreen;
         if (isStartShift) {
-            float desiredStart = -mOrientationHandler.getPrimarySize(taskPosition);
-            distanceToOffscreen = -mOrientationHandler.getEnd(taskPosition);
+            float desiredStart = -getPagedOrientationHandler().getPrimarySize(taskPosition);
+            distanceToOffscreen = -getPagedOrientationHandler().getEnd(taskPosition);
             if (mLastComputedTaskStartPushOutDistance == null) {
                 taskPosition.offsetTo(
-                        mOrientationHandler.getPrimaryValue(desiredStart, 0f),
-                        mOrientationHandler.getSecondaryValue(desiredStart, 0f));
+                        getPagedOrientationHandler().getPrimaryValue(desiredStart, 0f),
+                        getPagedOrientationHandler().getSecondaryValue(desiredStart, 0f));
                 getMatrix().mapRect(taskPosition);
-                mLastComputedTaskStartPushOutDistance = mOrientationHandler.getEnd(taskPosition)
-                        / mOrientationHandler.getPrimaryScale(this);
+                mLastComputedTaskStartPushOutDistance = getPagedOrientationHandler().getEnd(
+                        taskPosition) / getPagedOrientationHandler().getPrimaryScale(this);
             }
             distanceToOffscreen -= mLastComputedTaskStartPushOutDistance;
         } else {
-            float desiredStart = mOrientationHandler.getPrimarySize(this);
-            distanceToOffscreen = desiredStart - mOrientationHandler.getStart(taskPosition);
+            float desiredStart = getPagedOrientationHandler().getPrimarySize(this);
+            distanceToOffscreen = desiredStart - getPagedOrientationHandler().getStart(
+                    taskPosition);
             if (mLastComputedTaskEndPushOutDistance == null) {
                 taskPosition.offsetTo(
-                        mOrientationHandler.getPrimaryValue(desiredStart, 0f),
-                        mOrientationHandler.getSecondaryValue(desiredStart, 0f));
+                        getPagedOrientationHandler().getPrimaryValue(desiredStart, 0f),
+                        getPagedOrientationHandler().getSecondaryValue(desiredStart, 0f));
                 getMatrix().mapRect(taskPosition);
-                mLastComputedTaskEndPushOutDistance = (mOrientationHandler.getStart(taskPosition)
-                        - desiredStart) / mOrientationHandler.getPrimaryScale(this);
+                mLastComputedTaskEndPushOutDistance = (getPagedOrientationHandler().getStart(
+                        taskPosition) - desiredStart)
+                        / getPagedOrientationHandler().getPrimaryScale(this);
             }
             distanceToOffscreen -= mLastComputedTaskEndPushOutDistance;
         }
@@ -4606,7 +4644,7 @@
         if (isTopShift) {
             distanceToOffscreen = -taskPosition.bottom;
         } else if (isBottomShift) {
-            distanceToOffscreen = mActivity.getDeviceProfile().heightPx - taskPosition.top;
+            distanceToOffscreen = mContainer.getDeviceProfile().heightPx - taskPosition.top;
         }
         return distanceToOffscreen * offsetProgress;
     }
@@ -4661,8 +4699,8 @@
      * of split invocation as such.
      */
     public void initiateSplitSelect(TaskView taskView) {
-        int defaultSplitPosition = mOrientationHandler
-                .getDefaultSplitPosition(mActivity.getDeviceProfile());
+        int defaultSplitPosition = getPagedOrientationHandler()
+                .getDefaultSplitPosition(mContainer.getDeviceProfile());
         initiateSplitSelect(taskView, defaultSplitPosition, LAUNCHER_OVERVIEW_ACTIONS_SPLIT);
     }
 
@@ -4675,9 +4713,7 @@
         mSplitSelectStateController.setAnimateCurrentTaskDismissal(
                 true /*animateCurrentTaskDismissal*/);
         mSplitHiddenTaskViewIndex = indexOfChild(taskView);
-        if (isDesktopModeSupported()) {
-            updateDesktopTaskVisibility(false /* visible */);
-        }
+        updateDesktopTaskVisibility(false /* visible */);
     }
 
     /**
@@ -4699,9 +4735,7 @@
         mSplitSelectStateController.setInitialTaskSelect(splitSelectSource.intent,
                 splitSelectSource.position.stagePosition, splitSelectSource.itemInfo,
                 splitSelectSource.splitEvent, splitSelectSource.alreadyRunningTaskId);
-        if (isDesktopModeSupported()) {
-            updateDesktopTaskVisibility(false /* visible */);
-        }
+        updateDesktopTaskVisibility(false /* visible */);
     }
 
     private void updateDesktopTaskVisibility(boolean visible) {
@@ -4731,7 +4765,7 @@
             TaskThumbnailView thumbnail = taskIdAttributeContainer.getThumbnailView();
             mSplitSelectStateController.getSplitAnimationController()
                     .addInitialSplitFromPair(taskIdAttributeContainer, builder,
-                            mActivity.getDeviceProfile(),
+                            mContainer.getDeviceProfile(),
                             mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
                             primaryTaskSelected);
             builder.addOnFrameCallback(() ->{
@@ -4768,7 +4802,8 @@
      *          false otherwise
      */
     public boolean confirmSplitSelect(TaskView containerTaskView, Task task, Drawable drawable,
-            View secondView, @Nullable Bitmap thumbnail, Intent intent, UserHandle user) {
+            View secondView, @Nullable Bitmap thumbnail, Intent intent, UserHandle user,
+            ItemInfo itemInfo) {
         if (canLaunchFullscreenTask()) {
             return false;
         }
@@ -4787,9 +4822,9 @@
                                 + ") is not dockable / does not support splitscreen"));
                 return true;
             }
-            mSplitSelectStateController.setSecondTask(task);
+            mSplitSelectStateController.setSecondTask(task, itemInfo);
         } else {
-            mSplitSelectStateController.setSecondTask(intent, user);
+            mSplitSelectStateController.setSecondTask(intent, user, itemInfo);
         }
 
         RectF secondTaskStartingBounds = new RectF();
@@ -4798,17 +4833,20 @@
         Rect firstTaskStartingBounds = new Rect();
         Rect firstTaskEndingBounds = mTempRect;
 
-        boolean isTablet = mActivity.getDeviceProfile().isTablet;
+        boolean isTablet = mContainer.getDeviceProfile().isTablet;
         SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet);
         PendingAnimation pendingAnimation = new PendingAnimation(timings.getDuration());
 
         int halfDividerSize = getResources()
                 .getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
-        mOrientationHandler.getFinalSplitPlaceholderBounds(halfDividerSize,
-                mActivity.getDeviceProfile(),
+        getPagedOrientationHandler().getFinalSplitPlaceholderBounds(halfDividerSize,
+                mContainer.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds,
                 secondTaskEndingBounds);
 
+        mSplitDividerPlaceholderView = mSplitSelectStateController
+                .getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
+                        mContainer, secondTaskEndingBounds, getContext());
         FloatingTaskView firstFloatingTaskView =
                 mSplitSelectStateController.getFirstFloatingTaskView();
         firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
@@ -4818,7 +4856,7 @@
 
         safeRemoveDragLayerView(mSecondFloatingTaskView);
 
-        mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity, secondView,
+        mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mContainer, secondView,
                 thumbnail, drawable, secondTaskStartingBounds);
         mSecondFloatingTaskView.setAlpha(1);
         mSecondFloatingTaskView.addConfirmAnimation(pendingAnimation, secondTaskStartingBounds,
@@ -4836,8 +4874,7 @@
                         } else {
                             resetFromSplitSelectionState();
                         }
-                        InteractionJankMonitorWrapper.end(
-                                InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
+                        InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
                     });
         });
 
@@ -4847,8 +4884,8 @@
                     mSplitSelectStateController.getSecondTaskId());
         }
 
-        InteractionJankMonitorWrapper.begin(this,
-                InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "Second tile selected");
+        InteractionJankMonitorWrapper.begin(this, Cuj.CUJ_SPLIT_SCREEN_ENTER,
+                "Second tile selected");
 
         // Fade out all other views underneath placeholders
         ObjectAnimator tvFade = ObjectAnimator.ofFloat(this, RecentsView.CONTENT_ALPHA,1, 0);
@@ -4864,10 +4901,11 @@
             safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
             safeRemoveDragLayerView(mSecondFloatingTaskView);
             safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
+            safeRemoveDragLayerView(mSplitDividerPlaceholderView);
             mSecondFloatingTaskView = null;
             mSplitSelectSource = null;
             mSplitSelectStateController.getSplitAnimationController()
-                    .removeSplitInstructionsView(mActivity);
+                    .removeSplitInstructionsView(mContainer);
         }
 
         if (mSecondSplitHiddenView != null) {
@@ -4888,7 +4926,7 @@
         if (mSplitHiddenTaskViewIndex == -1) {
             return;
         }
-        if (!mActivity.getDeviceProfile().isTablet) {
+        if (!mContainer.getDeviceProfile().isTablet) {
             int pageToSnapTo = mCurrentPage;
             if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
                 pageToSnapTo += 1;
@@ -4905,14 +4943,12 @@
             mSplitHiddenTaskView.setThumbnailVisibility(VISIBLE, INVALID_TASK_ID);
             mSplitHiddenTaskView = null;
         }
-        if (isDesktopModeSupported()) {
-            updateDesktopTaskVisibility(true /* visible */);
-        }
+        updateDesktopTaskVisibility(true /* visible */);
     }
 
     private void safeRemoveDragLayerView(@Nullable View viewToRemove) {
         if (viewToRemove != null) {
-            mActivity.getDragLayer().removeView(viewToRemove);
+            mContainer.getDragLayer().removeView(viewToRemove);
         }
     }
 
@@ -4921,11 +4957,11 @@
      * Note that the translation can be its primary or secondary dimension.
      */
     public float getSplitSelectTranslation() {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+        RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
         int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
         int splitPlaceholderSize =
-                mActivity.getResources().getDimensionPixelSize(R.dimen.split_placeholder_size);
+                mContainer.getResources().getDimensionPixelSize(R.dimen.split_placeholder_size);
         int direction = orientationHandler.getSplitTranslationDirectionFactor(
                 splitPosition, deviceProfile);
 
@@ -4947,20 +4983,20 @@
     }
 
     protected void onRotateInSplitSelectionState() {
-        mOrientationHandler.getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
-                mSplitPlaceholderInset, mActivity.getDeviceProfile(),
+        getPagedOrientationHandler().getInitialSplitPlaceholderBounds(mSplitPlaceholderSize,
+                mSplitPlaceholderInset, mContainer.getDeviceProfile(),
                 mSplitSelectStateController.getActiveSplitStagePosition(), mTempRect);
         mTempRectF.set(mTempRect);
         FloatingTaskView firstFloatingTaskView =
                 mSplitSelectStateController.getFirstFloatingTaskView();
-        firstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
+        firstFloatingTaskView.updateOrientationHandler(getPagedOrientationHandler());
         firstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
 
-        PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
-        Pair<FloatProperty, FloatProperty> taskViewsFloat =
+        RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+        Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
                 orientationHandler.getSplitSelectTaskOffset(
                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
-                        mActivity.getDeviceProfile());
+                        mContainer.getDeviceProfile());
         taskViewsFloat.first.set(this, getSplitSelectTranslation());
         taskViewsFloat.second.set(this, 0f);
 
@@ -5061,7 +5097,7 @@
             float displacementX = tv.getWidth() * (toScale - 1f);
             float primaryTranslation = mIsRtl ? -displacementX : displacementX;
             anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
-                    mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation));
+                    getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation));
             int runningTaskIndex = getRunningTaskIndex();
             if (runningTaskIndex != -1 && runningTaskIndex != taskIndex
                     && getRemoteTargetHandles() != null) {
@@ -5077,7 +5113,7 @@
             if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
                 PropertyValuesHolder[] properties = new PropertyValuesHolder[3];
                 properties[0] = PropertyValuesHolder.ofFloat(
-                        mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation);
+                        getPagedOrientationHandler().getPrimaryViewTranslate(), primaryTranslation);
                 properties[1] = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
                 properties[2] = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
 
@@ -5093,9 +5129,21 @@
      * Returns the scale up required on the view, so that it coves the screen completely
      */
     public float getMaxScaleForFullScreen() {
-        getTaskSize(mTempRect);
+        if (enableGridOnlyOverview() && mContainer.getDeviceProfile().isTablet
+                && !mOverviewGridEnabled) {
+            if (mLastComputedCarouselTaskSize.isEmpty()) {
+                mSizeStrategy.calculateCarouselTaskSize(mContainer, mContainer.getDeviceProfile(),
+                        mLastComputedCarouselTaskSize, getPagedOrientationHandler());
+            }
+            mTempRect.set(mLastComputedCarouselTaskSize);
+        } else {
+            if (mLastComputedTaskSize.isEmpty()) {
+                getTaskSize(mLastComputedTaskSize);
+            }
+            mTempRect.set(mLastComputedTaskSize);
+        }
         return getPagedViewOrientedState().getFullScreenScaleAndPivot(
-                mTempRect, mActivity.getDeviceProfile(), mTempPointF);
+                mTempRect, mContainer.getDeviceProfile(), mTempPointF);
     }
 
     public PendingAnimation createTaskLaunchAnimation(
@@ -5121,10 +5169,10 @@
             // Once we pass a certain threshold, update the sysui flags to match the target
             // tasks' flags
             if (animator.getAnimatedFraction() > UPDATE_SYSUI_FLAGS_THRESHOLD) {
-                mActivity.getSystemUiController().updateUiState(
+                mContainer.getSystemUiController().updateUiState(
                         UI_STATE_FULLSCREEN_TASK, targetSysUiFlags);
             } else {
-                mActivity.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
+                mContainer.getSystemUiController().updateUiState(UI_STATE_FULLSCREEN_TASK, 0);
             }
 
             // Passing the threshold from taskview to fullscreen app will vibrate
@@ -5146,7 +5194,7 @@
         DepthController depthController = getDepthController();
         if (depthController != null) {
             ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth,
-                    MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mActivity));
+                    MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mContainer));
             anim.play(depthAnimator);
         }
         anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f));
@@ -5179,7 +5227,7 @@
                 }
                 Task task = tv.getTask();
                 if (task != null) {
-                    mActivity.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
+                    mContainer.getStatsLogManager().logger().withItemInfo(tv.getItemInfo())
                             .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN);
                 }
             } else {
@@ -5273,6 +5321,9 @@
     // TODO: To be removed in a follow up CL
     public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController,
             RecentsAnimationTargets recentsAnimationTargets) {
+        Log.d(TAG, "setRecentsAnimationTargets "
+                + "- recentsAnimationController: " + recentsAnimationController
+                + ", recentsAnimationTargets: " + recentsAnimationTargets);
         mRecentsAnimationController = recentsAnimationController;
         mSplitSelectStateController.setRecentsAnimationRunning(true);
         if (recentsAnimationTargets == null || recentsAnimationTargets.apps.length == 0) {
@@ -5280,7 +5331,7 @@
         }
 
         RemoteTargetGluer gluer;
-        if (isDesktopModeSupported() && recentsAnimationTargets.hasDesktopTasks()) {
+        if (recentsAnimationTargets.hasDesktopTasks()) {
             gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
                     true /* forDesktop */);
             mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
@@ -5303,7 +5354,7 @@
 
             TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
             tvs.setOrientationState(mOrientationState);
-            tvs.setDp(mActivity.getDeviceProfile());
+            tvs.setDp(mContainer.getDeviceProfile());
             tvs.recentsViewScale.value = 1;
         });
 
@@ -5335,8 +5386,14 @@
         finishRecentsAnimation(toRecents, true /* shouldPip */, onFinishComplete);
     }
 
+    /**
+     * NOTE: Whatever value gets passed through to the toRecents param may need to also be set on
+     * {@link #mRecentsAnimationController#setWillFinishToHome}.
+     */
     public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
             @Nullable Runnable onFinishComplete) {
+        Log.d(TAG, "finishRecentsAnimation - mRecentsAnimationController: "
+                + mRecentsAnimationController);
         // TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
         cleanupRemoteTargets();
 
@@ -5352,7 +5409,7 @@
             // Notify the SysUI to use fade-in animation when entering PiP from live tile.
             final SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(getContext());
             systemUiProxy.setPipAnimationTypeToAlpha();
-            systemUiProxy.setShelfHeight(true, mActivity.getDeviceProfile().hotseatBarSizePx);
+            systemUiProxy.setShelfHeight(true, mContainer.getDeviceProfile().hotseatBarSizePx);
             // Transaction to hide the task to avoid flicker for entering PiP from split-screen.
             // See also {@link AbsSwipeUpHandler#maybeFinishSwipeToHome}.
             PictureInPictureSurfaceTransaction tx =
@@ -5378,6 +5435,8 @@
      * Called when a running recents animation has finished or canceled.
      */
     public void onRecentsAnimationComplete() {
+        Log.d(TAG, "onRecentsAnimationComplete - mRecentsAnimationController: "
+                + mRecentsAnimationController);
         // At this point, the recents animation is not running and if the animation was canceled
         // by a display rotation then reset this state to show the screenshot
         setRunningTaskViewShowScreenshot(true);
@@ -5421,7 +5480,7 @@
 
     protected int getClearAllExtraPageSpacing() {
         return showAsGrid()
-                ? Math.max(mActivity.getDeviceProfile().overviewGridSideMargin - mPageSpacing, 0)
+                ? Math.max(mContainer.getDeviceProfile().overviewGridSideMargin - mPageSpacing, 0)
                 : 0;
     }
 
@@ -5453,10 +5512,6 @@
     }
 
     private int getFirstViewIndex() {
-        if (isDesktopModeSupported() && mDesktopTaskView != null) {
-            // Desktop task is at position 0, that is the first view
-            return 0;
-        }
         TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
         return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
     }
@@ -5497,8 +5552,8 @@
         // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
         // TaskViews. This must be called after laying out ClearAllButton.
         if (layoutChildren) {
-            int clearAllWidthDiff = mOrientationHandler.getPrimaryValue(mTaskWidth, mTaskHeight)
-                    - mOrientationHandler.getPrimarySize(mClearAllButton);
+            int clearAllWidthDiff = getPagedOrientationHandler().getPrimaryValue(mTaskWidth,
+                    mTaskHeight) - getPagedOrientationHandler().getPrimarySize(mClearAllButton);
             mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
         }
 
@@ -5506,7 +5561,7 @@
 
         int clearAllIndex = indexOfChild(mClearAllButton);
         int clearAllScroll = 0;
-        int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
+        int clearAllWidth = getPagedOrientationHandler().getPrimarySize(mClearAllButton);
         if (clearAllIndex != -1 && clearAllIndex < outPageScrolls.length) {
             float scrollDiff = mClearAllButton.getScrollAdjustment(showAsFullscreen, showAsGrid);
             clearAllScroll = newPageScrolls[clearAllIndex] + (int) scrollDiff;
@@ -5521,7 +5576,7 @@
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
             float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
-            int pageScroll = newPageScrolls[i] + (int) scrollDiff;
+            int pageScroll = newPageScrolls[i] + Math.round(scrollDiff);
             if ((mIsRtl && pageScroll < lastTaskScroll)
                     || (!mIsRtl && pageScroll > lastTaskScroll)) {
                 pageScroll = lastTaskScroll;
@@ -5575,6 +5630,19 @@
     }
 
     /**
+     * Returns how many pixels the running task is offset on the currently laid out dominant axis
+     * specifically during a Keyboard task focus.
+     */
+    public int getScrollOffsetForKeyboardTaskFocus() {
+        if (!isKeyboardTaskFocusPending()) {
+            return getScrollOffset(getRunningTaskIndex());
+        }
+        return getPagedOrientationHandler().getPrimaryScroll(this)
+                - getScrollForPage(mKeyboardTaskFocusIndex)
+                + getScrollOffset(getRunningTaskIndex());
+    }
+
+    /**
      * Sets whether or not we should clamp the scroll offset.
      * This is used to avoid x-axis movement when swiping up transient taskbar.
      * Should only be set at the beginning and end of the gesture, otherwise a jump may occur.
@@ -5607,15 +5675,15 @@
         if (pageIndex == -1) {
             return 0;
         }
-
-        int overScrollShift = getOverScrollShift();
-        if (mAdjacentPageHorizontalOffset > 0) {
-            // Don't dampen the scroll (due to overscroll) if the adjacent tasks are offscreen, so
-            // that the page can move freely given there's no visual indication why it shouldn't.
-            overScrollShift = (int) Utilities.mapRange(mAdjacentPageHorizontalOffset,
-                    overScrollShift, getUndampedOverScrollShift());
-        }
-        return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this)
+        // Don't dampen the scroll (due to overscroll) if the adjacent tasks are offscreen, so that
+        // the page can move freely given there's no visual indication why it shouldn't.
+        int overScrollShift = mAdjacentPageHorizontalOffset > 0
+                        ? (int) Utilities.mapRange(
+                                mAdjacentPageHorizontalOffset,
+                                getOverScrollShift(),
+                                getUndampedOverScrollShift())
+                        : getOverScrollShift();
+        return getScrollForPage(pageIndex) - getPagedOrientationHandler().getPrimaryScroll(this)
                 + overScrollShift + getOffsetFromScrollPosition(pageIndex);
     }
 
@@ -5684,7 +5752,7 @@
     public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
         float degreesRotated;
         if (navbarRotation == 0) {
-            degreesRotated = mOrientationHandler.getDegreesRotated();
+            degreesRotated = getPagedOrientationHandler().getDegreesRotated();
         } else {
             degreesRotated = -navbarRotation;
         }
@@ -5711,11 +5779,20 @@
     }
 
     private void updateEnabledOverlays() {
+        TaskView focusedTaskView = getFocusedTaskView();
         int taskCount = getTaskViewCount();
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
+            if (taskView == focusedTaskView) {
+                continue;
+            }
             taskView.setOverlayEnabled(mOverlayEnabled && isTaskViewFullyVisible(taskView));
         }
+        // Focus task overlay should be enabled and refreshed at last
+        if (focusedTaskView != null) {
+            focusedTaskView.setOverlayEnabled(
+                    mOverlayEnabled && isTaskViewFullyVisible(focusedTaskView));
+        }
     }
 
     public void setOverlayEnabled(boolean overlayEnabled) {
@@ -5852,7 +5929,7 @@
         return mTaskOverlayFactory;
     }
 
-    public BaseActivityInterface getSizeStrategy() {
+    public BaseContainerInterface getSizeStrategy() {
         return mSizeStrategy;
     }
 
@@ -5869,7 +5946,8 @@
             return;
         }
 
-        mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
+        mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT,
+                show ? FOREGROUND_SCRIM_TINT : 0f);
         mTintingAnimator.setAutoCancel(true);
         mTintingAnimator.start();
     }
@@ -5883,7 +5961,7 @@
             requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
         }
 
-        Drawable scrimBg = mActivity.getScrimView().getBackground();
+        Drawable scrimBg = mContainer.getScrimView().getBackground();
         if (scrimBg != null) {
             if (tintAmount == 0f) {
                 scrimBg.setTintList(null);
@@ -5902,8 +5980,8 @@
     /** Returns {@code true} if the overview tasks are displayed as a grid. */
     public boolean showAsGrid() {
         return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
-                && mSizeStrategy.stateFromGestureEndTarget(
-                mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
+                && mSizeStrategy.stateFromGestureEndTarget(mCurrentGestureEndTarget)
+                    .displayOverviewTasksAsGrid(mContainer.getDeviceProfile()));
     }
 
     private boolean showAsFullscreen() {
@@ -5912,6 +5990,7 @@
     }
 
     public void cleanupRemoteTargets() {
+        Log.d(TAG, "cleanupRemoteTargets");
         mRemoteTargetHandles = null;
     }
 
@@ -6014,11 +6093,50 @@
         dispatchScrollChanged();
     }
 
+    /**
+     * Prepares this RecentsView to scroll properly for an upcoming child view focus request from
+     * keyboard quick switching
+     */
+    public void setKeyboardTaskFocusIndex(int taskIndex) {
+        mKeyboardTaskFocusIndex = taskIndex;
+    }
+
+    /** Returns whether this RecentsView will be scrolling to a child view for a focus request */
+    public boolean isKeyboardTaskFocusPending() {
+        return mKeyboardTaskFocusIndex != INVALID_PAGE;
+    }
+
+    private boolean isKeyboardTaskFocusPendingForChild(View child) {
+        return isKeyboardTaskFocusPending() && mKeyboardTaskFocusIndex == indexOfChild(child);
+    }
+
     @Override
-    protected boolean shouldHandleRequestChildFocus() {
-        // If we are already scrolling to a task view, then the focus request has already been
-        // handled
-        return mScroller.isFinished();
+    protected int getSnapAnimationDuration() {
+        return isKeyboardTaskFocusPending()
+                ? mKeyboardTaskFocusSnapAnimationDuration : super.getSnapAnimationDuration();
+    }
+
+    @Override
+    protected void onVelocityValuesUpdated() {
+        super.onVelocityValuesUpdated();
+        mKeyboardTaskFocusSnapAnimationDuration =
+                getResources().getInteger(R.integer.config_keyboardTaskFocusSnapAnimationDuration);
+    }
+
+    @Override
+    protected boolean shouldHandleRequestChildFocus(View child) {
+        // If we are already scrolling to a task view and we aren't focusing to this child from
+        // keyboard quick switch, then the focus request has already been handled
+        return mScroller.isFinished() || isKeyboardTaskFocusPendingForChild(child);
+    }
+
+    @Override
+    public void requestChildFocus(View child, View focused) {
+        if (isKeyboardTaskFocusPendingForChild(child)) {
+            updateGridProperties();
+            updateScrollSynchronously();
+        }
+        super.requestChildFocus(child, focused);
     }
 
     private void dispatchScrollChanged() {
@@ -6029,7 +6147,7 @@
         }
     }
 
-    private static class PinnedStackAnimationListener<T extends BaseActivity> extends
+    private static class PinnedStackAnimationListener<T extends RecentsViewContainer> extends
             IPipAnimationListener.Stub {
         @Nullable
         private T mActivity;
@@ -6077,9 +6195,7 @@
 
     /** Get the color used for foreground scrimming the RecentsView for sharing. */
     public static int getForegroundScrimDimColor(Context context) {
-        int baseColor = Themes.getAttrColor(context, R.attr.overviewScrimColor);
-        // The Black blending is temporary until we have the proper color token.
-        return ColorUtils.blendARGB(Color.BLACK, baseColor, 0.25f);
+        return context.getColor(R.color.overview_foreground_scrim_color);
     }
 
     /** Get the RecentsAnimationController */
@@ -6097,7 +6213,7 @@
     public void updateLocusId() {
         String locusId = "Overview";
 
-        if (mOverviewStateEnabled && mActivity.isStarted()) {
+        if (mOverviewStateEnabled && mContainer.isStarted()) {
             locusId += "|ENABLED";
         } else {
             locusId += "|DISABLED";
@@ -6105,7 +6221,28 @@
 
         final LocusId id = new LocusId(locusId);
         // Set locus context is a binder call, don't want it to happen during a transition
-        UI_HELPER_EXECUTOR.post(() -> mActivity.setLocusContext(id, Bundle.EMPTY));
+        UI_HELPER_EXECUTOR.post(() -> mContainer.setLocusContext(id, Bundle.EMPTY));
+    }
+
+    /**
+     * Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded.
+     */
+    public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
+            Runnable successCallback) {
+        if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
+            return;
+        }
+        switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false,
+                () -> moveTaskToDesktopInternal(taskContainer, successCallback)));
+    }
+
+    private void moveTaskToDesktopInternal(TaskIdAttributeContainer taskContainer,
+            Runnable successCallback) {
+        if (mDesktopRecentsTransitionController == null) {
+            return;
+        }
+        mDesktopRecentsTransitionController.moveToDesktop(taskContainer.getTask().key.id);
+        successCallback.run();
     }
 
     public interface TaskLaunchListener {
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index f6501f1..a56d51e 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -16,21 +16,35 @@
 
 package com.android.quickstep.views;
 
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.content.Context;
-import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.launcher3.LauncherState;
+import com.android.app.animation.Interpolators;
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.states.StateAnimationConfig;
+
+import com.android.quickstep.util.SplitSelectStateController;
 
 /**
  * A rounded rectangular component containing a single TextView.
@@ -40,7 +54,12 @@
  * Appears and disappears concurrently with a FloatingTaskView.
  */
 public class SplitInstructionsView extends LinearLayout {
-    private final StatefulActivity mLauncher;
+    private static final int BOUNCE_DURATION = 250;
+    private static final float BOUNCE_HEIGHT = 20;
+    private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350;
+
+    private final RecentsViewContainer mContainer;
+    public boolean mIsCurrentlyAnimating = false;
 
     public static final FloatProperty<SplitInstructionsView> UNFOLD =
             new FloatProperty<>("SplitInstructionsUnfold") {
@@ -55,6 +74,19 @@
                 }
             };
 
+    public static final FloatProperty<SplitInstructionsView> TRANSLATE_Y =
+            new FloatProperty<>("SplitInstructionsTranslateY") {
+                @Override
+                public void setValue(SplitInstructionsView splitInstructionsView, float v) {
+                    splitInstructionsView.setTranslationY(v);
+                }
+
+                @Override
+                public Float get(SplitInstructionsView splitInstructionsView) {
+                    return splitInstructionsView.getTranslationY();
+                }
+            };
+
     public SplitInstructionsView(Context context) {
         this(context, null);
     }
@@ -65,13 +97,13 @@
 
     public SplitInstructionsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mLauncher = (StatefulActivity) context;
+        mContainer = RecentsViewContainer.containerFromContext(context);
     }
 
-    public static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) {
-        ViewGroup dragLayer = launcher.getDragLayer();
+    public static SplitInstructionsView getSplitInstructionsView(RecentsViewContainer container) {
+        ViewGroup dragLayer = container.getDragLayer();
         final SplitInstructionsView splitInstructionsView =
-                (SplitInstructionsView) launcher.getLayoutInflater().inflate(
+                (SplitInstructionsView) container.getLayoutInflater().inflate(
                         R.layout.split_instructions_view,
                         dragLayer,
                         false
@@ -95,52 +127,87 @@
 
     private void init() {
         TextView cancelTextView = findViewById(R.id.split_instructions_text_cancel);
+        TextView instructionTextView = findViewById(R.id.split_instructions_text);
 
         if (FeatureFlags.enableSplitContextually()) {
             cancelTextView.setVisibility(VISIBLE);
             cancelTextView.setOnClickListener((v) -> exitSplitSelection());
+            instructionTextView.setText(R.string.toast_contextual_split_select_app);
         }
+
+        // Set accessibility title, will be announced by a11y tools.
+        instructionTextView.setAccessibilityPaneTitle(instructionTextView.getText());
     }
 
     private void exitSplitSelection() {
-        ((RecentsView) mLauncher.getOverviewPanel()).getSplitSelectController()
-                .getSplitAnimationController().playPlaceholderDismissAnim(mLauncher);
-        mLauncher.getStateManager().goToState(LauncherState.NORMAL);
-    }
+        RecentsView recentsView = mContainer.getOverviewPanel();
+        SplitSelectStateController splitSelectController = recentsView.getSplitSelectController();
 
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        if (!FeatureFlags.enableSplitContextually()) {
-            return;
+        StateManager stateManager = recentsView.getStateManager();
+        BaseState startState = stateManager.getState();
+        long duration = startState.getTransitionDuration(mContainer.asContext(), false);
+        if (duration == 0) {
+            // Case where we're in contextual on workspace (NORMAL), which by default has 0
+            // transition duration
+            duration = DURATION_DEFAULT_SPLIT_DISMISS;
         }
-
-        info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
-                R.string.toast_split_select_cont_desc,
-                getResources().getString(R.string.toast_split_select_cont_desc)
-        ));
-    }
-
-    @Override
-    public boolean performAccessibilityAction(int action, Bundle arguments) {
-        if (!FeatureFlags.enableSplitContextually()) {
-            return super.performAccessibilityAction(action, arguments);
-        }
-
-        if (action == R.string.toast_split_select_cont_desc) {
-            exitSplitSelection();
-            return true;
-        }
-        return super.performAccessibilityAction(action, arguments);
+        StateAnimationConfig config = new StateAnimationConfig();
+        config.duration = duration;
+        AnimatorSet stateAnim = stateManager.createAtomicAnimation(
+                startState, NORMAL, config);
+        AnimatorSet dismissAnim = splitSelectController.getSplitAnimationController()
+                .createPlaceholderDismissAnim(mContainer,
+                        LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON, duration);
+        stateAnim.play(dismissAnim);
+        stateManager.setCurrentAnimation(stateAnim, NORMAL);
+        stateAnim.start();
     }
 
     void ensureProperRotation() {
-        ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler()
+        ((RecentsView) mContainer.getOverviewPanel()).getPagedOrientationHandler()
                 .setSplitInstructionsParams(
                         this,
-                        mLauncher.getDeviceProfile(),
+                        mContainer.getDeviceProfile(),
                         getMeasuredHeight(),
                         getMeasuredWidth()
                 );
     }
+
+    /**
+     * Draws attention to the split instructions view by bouncing it up and down.
+     */
+    public void goBoing() {
+        if (mIsCurrentlyAnimating) {
+            return;
+        }
+
+        float restingY = getTranslationY();
+        float bounceToY = restingY - Utilities.dpToPx(BOUNCE_HEIGHT);
+        PendingAnimation anim = new PendingAnimation(BOUNCE_DURATION);
+        // Animate the view lifting up to a higher position
+        anim.addFloat(this, TRANSLATE_Y, restingY, bounceToY, Interpolators.STANDARD);
+
+        anim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mIsCurrentlyAnimating = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                // Create a low stiffness, medium bounce spring centering at the rest position
+                SpringForce spring = new SpringForce(restingY)
+                        .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+                        .setStiffness(SpringForce.STIFFNESS_LOW);
+                // Animate the view getting pulled back to rest position by the spring
+                SpringAnimation springAnim = new SpringAnimation(SplitInstructionsView.this,
+                        DynamicAnimation.TRANSLATION_Y).setSpring(spring).setStartValue(bounceToY);
+
+                springAnim.addEndListener((a, b, c, d) -> mIsCurrentlyAnimating = false);
+                springAnim.start();
+            }
+        });
+
+        anim.buildAnim().start();
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index cf89d2e..fcbb45b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -18,12 +18,16 @@
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -42,16 +46,15 @@
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.TaskCornerRadius;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
 
@@ -65,18 +68,18 @@
     private static final int REVEAL_OPEN_DURATION = enableOverviewIconMenu() ? 417 : 150;
     private static final int REVEAL_CLOSE_DURATION = enableOverviewIconMenu() ? 333 : 100;
 
-    private BaseDraggingActivity mActivity;
+    private RecentsViewContainer mContainer;
     private TextView mTaskName;
     @Nullable
     private AnimatorSet mOpenCloseAnimator;
+    @Nullable
+    private ValueAnimator mRevealAnimator;
     @Nullable private Runnable mOnClosingStartCallback;
     private TaskView mTaskView;
     private TaskIdAttributeContainer mTaskContainer;
     private LinearLayout mOptionLayout;
     private float mMenuTranslationYBeforeOpen;
     private float mMenuTranslationXBeforeOpen;
-    private float mIconViewTranslationYBeforeOpen;
-    private float mIconViewTranslationXBeforeOpen;
 
     public TaskMenuView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -85,7 +88,7 @@
     public TaskMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        mActivity = BaseDraggingActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
         setClipToOutline(true);
     }
 
@@ -99,7 +102,7 @@
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            BaseDragLayer dl = mActivity.getDragLayer();
+            BaseDragLayer dl = mContainer.getDragLayer();
             if (!dl.isEventOverView(this, ev)) {
                 // TODO: log this once we have a new container type for it?
                 close(true);
@@ -111,13 +114,10 @@
 
     @Override
     protected void handleClose(boolean animate) {
-        if (animate) {
+        if (animate || enableOverviewIconMenu()) {
             animateClose();
         } else {
             closeComplete();
-            if (enableOverviewIconMenu()) {
-                ((IconAppChipView) mTaskContainer.getIconView()).reset();
-            }
         }
     }
 
@@ -137,6 +137,20 @@
         };
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (!(enableOverviewIconMenu()
+                && ((RecentsView) mContainer.getOverviewPanel()).isOnGridBottomRow(mTaskView))) {
+            // TODO(b/326952853): Cap menu height for grid bottom row in a way that doesn't break
+            // additionalTranslationY.
+            int maxMenuHeight = calculateMaxHeight();
+            if (MeasureSpec.getSize(heightMeasureSpec) > maxMenuHeight) {
+                heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
     public void onRotationChanged() {
         if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
             mOpenCloseAnimator.end();
@@ -151,10 +165,10 @@
 
     public static boolean showForTask(TaskIdAttributeContainer taskContainer,
             @Nullable Runnable onClosingStartCallback) {
-        BaseDraggingActivity activity = BaseDraggingActivity.fromContext(
+        RecentsViewContainer container = RecentsViewContainer.containerFromContext(
                 taskContainer.getTaskView().getContext());
-        final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
-                        R.layout.task_menu, activity.getDragLayer(), false);
+        final TaskMenuView taskMenuView = (TaskMenuView) container.getLayoutInflater().inflate(
+                        R.layout.task_menu, container.getDragLayer(), false);
         taskMenuView.setOnClosingStartCallback(onClosingStartCallback);
         return taskMenuView.populateAndShowForTask(taskContainer);
     }
@@ -167,7 +181,7 @@
         if (isAttachedToWindow()) {
             return false;
         }
-        mActivity.getDragLayer().addView(this);
+        mContainer.getDragLayer().addView(this);
         mTaskView = taskContainer.getTaskView();
         mTaskContainer = taskContainer;
         if (!populateAndLayoutMenu()) {
@@ -200,7 +214,7 @@
     }
 
     private void addMenuOption(SystemShortcut menuOption) {
-        LinearLayout menuOptionView = (LinearLayout) mActivity.getLayoutInflater().inflate(
+        LinearLayout menuOptionView = (LinearLayout) mContainer.getLayoutInflater().inflate(
                 R.layout.task_view_menu_option, this, false);
         if (enableOverviewIconMenu()) {
             ((GradientDrawable) menuOptionView.getBackground()).setCornerRadius(0);
@@ -209,7 +223,7 @@
                 menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text));
         LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
         mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp,
-                menuOptionView, mActivity.getDeviceProfile());
+                menuOptionView, mContainer.getDeviceProfile());
         // Set an onClick listener on each menu option. The onClick method is responsible for
         // ending LiveTile mode on the thumbnail if needed.
         menuOptionView.setOnClickListener(menuOption::onClick);
@@ -217,16 +231,19 @@
     }
 
     private void orientAroundTaskView(TaskIdAttributeContainer taskContainer) {
-        RecentsView recentsView = mActivity.getOverviewPanel();
-        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        RecentsView recentsView = mContainer.getOverviewPanel();
+        RecentsPagedOrientationHandler orientationHandler =
+                recentsView.getPagedOrientationHandler();
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
 
         // Get Position
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        mActivity.getDragLayer().getDescendantRectRelativeToSelf(
-                enableOverviewIconMenu() ? taskContainer.getIconView().asView()
-                        : taskContainer.getThumbnailView(), sTempRect);
-        Rect insets = mActivity.getDragLayer().getInsets();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+        mContainer.getDragLayer().getDescendantRectRelativeToSelf(
+                enableOverviewIconMenu()
+                        ? getIconView().findViewById(R.id.icon_view_menu_anchor)
+                        : taskContainer.getThumbnailView(),
+                sTempRect);
+        Rect insets = mContainer.getDragLayer().getInsets();
         BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
         params.width = orientationHandler.getTaskMenuWidth(taskContainer.getThumbnailView(),
                 deviceProfile, taskContainer.getStagePosition());
@@ -245,15 +262,9 @@
 
         orientationHandler.setTaskOptionsMenuLayoutOrientation(
                 deviceProfile, mOptionLayout, dividerSpacing, divider);
-        float thumbnailAlignedX = sTempRect.left - insets.left + (enableOverviewIconMenu()
-                ? -getResources().getDimensionPixelSize(
-                        R.dimen.task_thumbnail_icon_menu_touch_max_margin)
-                        - getResources().getDimension(R.dimen.task_thumbnail_icon_menu_start_margin)
-                : 0);
-        float thumbnailAlignedY = sTempRect.top - insets.top + (enableOverviewIconMenu()
-                ? getResources().getDimensionPixelSize(R.dimen.task_thumbnail_icon_menu_max_height)
-                        - getResources().getDimensionPixelSize(
-                        R.dimen.task_thumbnail_icon_menu_top_margin) : 0);
+        float thumbnailAlignedX = sTempRect.left - insets.left;
+        float thumbnailAlignedY = sTempRect.top - insets.top;
+
         // Changing pivot to make computations easier
         // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
         // which would render the X and Y position set here incorrect
@@ -261,81 +272,86 @@
         setPivotY(0);
         setRotation(orientationHandler.getDegreesRotated());
 
-        // Margin that insets the menuView inside the taskView
-        float taskInsetMarginX = enableOverviewIconMenu() ? getResources().getDimension(
-                R.dimen.task_thumbnail_icon_menu_start_margin) : getResources().getDimension(
-                R.dimen.task_card_margin);
-        float taskInsetMarginY = enableOverviewIconMenu() ? getResources().getDimension(
-                R.dimen.task_thumbnail_icon_menu_start_margin) : getResources().getDimension(
-                R.dimen.task_card_margin);
-        setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
-                mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMarginX,
-                mTaskContainer.getIconView().asView()));
-        setTranslationY(orientationHandler.getTaskMenuY(
-                thumbnailAlignedY, mTaskContainer.getThumbnailView(),
-                mTaskContainer.getStagePosition(), this, taskInsetMarginY,
-                mTaskContainer.getIconView().asView()));
+        if (enableOverviewIconMenu()) {
+            setTranslationX(thumbnailAlignedX);
+            setTranslationY(thumbnailAlignedY);
+        } else {
+            // Margin that insets the menuView inside the taskView
+            float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+            setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
+                    mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin,
+                    getIconView()));
+            setTranslationY(orientationHandler.getTaskMenuY(
+                    thumbnailAlignedY, mTaskContainer.getThumbnailView(),
+                    mTaskContainer.getStagePosition(), this, taskInsetMargin,
+                    getIconView()));
+        }
     }
 
     private void animateOpen() {
         mMenuTranslationYBeforeOpen = getTranslationY();
         mMenuTranslationXBeforeOpen = getTranslationX();
-        mIconViewTranslationYBeforeOpen = mTaskContainer.getIconView().asView().getTranslationY();
-        mIconViewTranslationXBeforeOpen = mTaskContainer.getIconView().asView().getTranslationX();
         animateOpenOrClosed(false);
         mIsOpen = true;
     }
 
+    private View getIconView() {
+        return mTaskContainer.getIconView().asView();
+    }
+
     private void animateClose() {
         animateOpenOrClosed(true);
     }
 
     private void animateOpenOrClosed(boolean closing) {
         if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
-            mOpenCloseAnimator.end();
+            testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "getting canceled");
+            mOpenCloseAnimator.cancel();
         }
         mOpenCloseAnimator = new AnimatorSet();
-
-        final Animator revealAnimator = createOpenCloseOutlineProvider()
-                .createRevealAnimator(this, closing);
-        revealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
+        // If we're opening, we just start from the beginning as a new `TaskMenuView` is created
+        // each time we do the open animation so there will never be a partial value here.
+        float revealAnimationStartProgress = 0f;
+        if (closing && mRevealAnimator != null) {
+            revealAnimationStartProgress = 1f - mRevealAnimator.getAnimatedFraction();
+        }
+        mRevealAnimator = createOpenCloseOutlineProvider()
+                .createRevealAnimator(this, closing, revealAnimationStartProgress);
+        mRevealAnimator.setInterpolator(enableOverviewIconMenu() ? Interpolators.EMPHASIZED
                 : Interpolators.DECELERATE);
 
         if (enableOverviewIconMenu()) {
+            IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView();
+
             float additionalTranslationY = 0;
-            if (((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView)) {
+            if (((RecentsView) mContainer.getOverviewPanel()).isOnGridBottomRow(mTaskView)) {
                 // Animate menu up for enough room to display full menu when task on bottom row.
                 float menuBottom = getHeight() + mMenuTranslationYBeforeOpen;
                 float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY();
-                float taskbarTop = mActivity.getDeviceProfile().heightPx
-                        - mActivity.getDeviceProfile().getOverviewActionsClaimedSpaceBelow();
+                float taskbarTop = mContainer.getDeviceProfile().heightPx
+                        - mContainer.getDeviceProfile().getOverviewActionsClaimedSpaceBelow();
                 float midpoint = (taskBottom + taskbarTop) / 2f;
                 additionalTranslationY = -Math.max(menuBottom - midpoint, 0);
             }
-            // Translate the menu to account for the expansion of the app chip menu as well.
-            float expandOffsetTranslationY = getResources().getDimensionPixelSize(
-                    R.dimen.task_thumbnail_icon_menu_expanded_gap);
             ObjectAnimator translationYAnim = ObjectAnimator.ofFloat(this, TRANSLATION_Y,
                     closing ? mMenuTranslationYBeforeOpen
-                            : mMenuTranslationYBeforeOpen + additionalTranslationY
-                                    + expandOffsetTranslationY);
+                            : mMenuTranslationYBeforeOpen + additionalTranslationY);
             translationYAnim.setInterpolator(EMPHASIZED);
 
             ObjectAnimator menuTranslationYAnim = ObjectAnimator.ofFloat(
-                    mTaskContainer.getIconView().asView(), TRANSLATION_Y,
-                    closing ? mIconViewTranslationYBeforeOpen
-                            : mIconViewTranslationYBeforeOpen + additionalTranslationY);
+                    iconAppChip.getMenuTranslationY(),
+                    MULTI_PROPERTY_VALUE, closing ? 0 : additionalTranslationY);
             menuTranslationYAnim.setInterpolator(EMPHASIZED);
 
-            mOpenCloseAnimator.playTogether(translationYAnim, menuTranslationYAnim);
-        }
-        // Animate menu and icon when split task would display off the side of the screen.
-        if (enableOverviewIconMenu() && mActivity.getDeviceProfile().isLandscape
-                && mTaskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT) {
-            float additionalTranslationX = Math.max(
-                    getTranslationX() + getWidth() - (mActivity.getDeviceProfile().widthPx
-                            - getResources().getDimensionPixelSize(
-                            R.dimen.task_menu_edge_padding) * 2), 0);
+            float additionalTranslationX = 0;
+            if (mContainer.getDeviceProfile().isLandscape
+                    && mTaskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT) {
+                // Animate menu and icon when split task would display off the side of the screen.
+                additionalTranslationX = Math.max(
+                        getTranslationX() + getWidth() - (mContainer.getDeviceProfile().widthPx
+                                - getResources().getDimensionPixelSize(
+                                R.dimen.task_menu_edge_padding) * 2), 0);
+            }
 
             ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X,
                     closing ? mMenuTranslationXBeforeOpen
@@ -343,15 +359,18 @@
             translationXAnim.setInterpolator(EMPHASIZED);
 
             ObjectAnimator menuTranslationXAnim = ObjectAnimator.ofFloat(
-                    mTaskContainer.getIconView().asView(), TRANSLATION_X,
-                    closing ? mIconViewTranslationXBeforeOpen
-                            : mIconViewTranslationXBeforeOpen - additionalTranslationX);
+                    iconAppChip.getMenuTranslationX(),
+                    MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
             menuTranslationXAnim.setInterpolator(EMPHASIZED);
+            testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+                    "TaskMenuView.java.animateOpenOrClosed: running translation animations");
 
-            mOpenCloseAnimator.playTogether(translationXAnim, menuTranslationXAnim);
+            mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
+                    menuTranslationXAnim, menuTranslationYAnim);
         }
-
-        mOpenCloseAnimator.playTogether(revealAnimator,
+        testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+                "TaskMenuView.java.animateOpenOrClosed: running animation 2");
+        mOpenCloseAnimator.playTogether(mRevealAnimator,
                 ObjectAnimator.ofFloat(
                         mTaskContainer.getThumbnailView(), DIM_ALPHA,
                         closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA),
@@ -359,6 +378,8 @@
         mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
+                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+                        "TaskMenuView.java.animateOpenOrClosed: onAnimationStart");
                 setVisibility(VISIBLE);
                 if (closing && mOnClosingStartCallback != null) {
                     mOnClosingStartCallback.run();
@@ -366,7 +387,16 @@
             }
 
             @Override
+            public void onAnimationCancel(Animator animation) {
+                super.onAnimationCancel(animation);
+                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+                        "TaskMenuView.java.animateOpenOrClosed: onAnimationCancel");
+            }
+
+            @Override
             public void onAnimationSuccess(Animator animator) {
+                testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
+                        "TaskMenuView.java.animateOpenOrClosed: onAnimationSuccess");
                 if (closing) {
                     closeComplete();
                 }
@@ -377,8 +407,10 @@
     }
 
     private void closeComplete() {
+        testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "TaskMenuView.java.closeComplete");
         mIsOpen = false;
-        mActivity.getDragLayer().removeView(this);
+        mContainer.getDragLayer().removeView(this);
+        mRevealAnimator = null;
     }
 
     private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
@@ -392,6 +424,17 @@
         return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
     }
 
+    /**
+     * Calculates max height based on how much space we have available.
+     * If not enough space then the view will scroll. The maximum menu size will sit inside the task
+     * with a margin on the top and bottom.
+     */
+    private int calculateMaxHeight() {
+        float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+        return mTaskView.getPagedOrientationHandler().getTaskMenuHeight(taskInsetMargin,
+                mContainer.getDeviceProfile(), getTranslationX(), getTranslationY());
+    }
+
     private void setOnClosingStartCallback(Runnable onClosingStartCallback) {
         mOnClosingStartCallback = onClosingStartCallback;
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index 12b8b6f..1db04a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -29,7 +29,6 @@
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import android.widget.LinearLayout
-import com.android.launcher3.BaseDraggingActivity
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.InsettableFrameLayout
 import com.android.launcher3.R
@@ -40,24 +39,22 @@
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
 
-class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
+class TaskMenuViewWithArrow<T> : ArrowPopup<T> where T : RecentsViewContainer, T : Context {
     companion object {
         const val TAG = "TaskMenuViewWithArrow"
 
-        fun showForTask(
+        fun <T> showForTask(
             taskContainer: TaskIdAttributeContainer,
             alignedOptionIndex: Int = 0
-        ): Boolean {
-            val activity =
-                BaseDraggingActivity.fromContext<BaseDraggingActivity>(
-                    taskContainer.taskView.context
-                )
+        ): Boolean where T : RecentsViewContainer, T : Context {
+            val container: RecentsViewContainer =
+                RecentsViewContainer.containerFromContext(taskContainer.taskView.context)
             val taskMenuViewWithArrow =
-                activity.layoutInflater.inflate(
+                container.layoutInflater.inflate(
                     R.layout.task_menu_with_arrow,
-                    activity.dragLayer,
+                    container.dragLayer,
                     false
-                ) as TaskMenuViewWithArrow<*>
+                ) as TaskMenuViewWithArrow<T>
 
             return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignedOptionIndex)
         }
@@ -124,6 +121,25 @@
         optionLayout = requireViewById(R.id.menu_option_layout)
     }
 
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        val maxMenuHeight: Int = calculateMaxHeight()
+        val newHeightMeasureSpec =
+            if (MeasureSpec.getSize(heightMeasureSpec) > maxMenuHeight) {
+                MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST)
+            } else heightMeasureSpec
+        super.onMeasure(widthMeasureSpec, newHeightMeasureSpec)
+    }
+
+    private fun calculateMaxHeight(): Int {
+        val taskInsetMargin = resources.getDimension(R.dimen.task_card_margin)
+        return taskView.pagedOrientationHandler.getTaskMenuHeight(
+            taskInsetMargin,
+            mActivityContext.deviceProfile,
+            translationX,
+            translationY
+        )
+    }
+
     private fun populateAndShowForTask(
         taskContainer: TaskIdAttributeContainer,
         alignedOptionIndex: Int
@@ -331,7 +347,7 @@
 
     override fun updateArrowColor() {
         mArrow.background =
-            RoundedArrowDrawable(
+            RoundedArrowDrawable.createHorizontalRoundedArrow(
                 mArrowWidth.toFloat(),
                 mArrowHeight.toFloat(),
                 mArrowPointRadius.toFloat(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index dff0580..7e46739 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -48,14 +48,13 @@
 import androidx.annotation.RequiresApi;
 import androidx.core.graphics.ColorUtils;
 
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -122,7 +121,7 @@
                 }
             };
 
-    private final BaseActivity mActivity;
+    private final RecentsViewContainer mContainer;
     @Nullable
     private TaskOverlay mOverlay;
     private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -171,7 +170,7 @@
         mBackgroundPaint.setColor(Color.WHITE);
         mSplashBackgroundPaint.setColor(Color.WHITE);
         mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-        mActivity = BaseActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
         // Initialize with placeholder value. It is overridden later by TaskView
         mFullscreenParams = TEMP_PARAMS.get(context);
 
@@ -308,7 +307,7 @@
         RectF boundsInBitmapSpace = new RectF();
         boundsToBitmapSpace.mapRect(boundsInBitmapSpace, viewRect);
 
-        DeviceProfile dp = mActivity.getDeviceProfile();
+        DeviceProfile dp = mContainer.getDeviceProfile();
         int bottomInset = dp.isTablet
                 ? Math.round(bitmapRect.bottom - boundsInBitmapSpace.bottom) : 0;
         return Insets.of(0, 0, 0, bottomInset);
@@ -513,7 +512,7 @@
             return false;
         }
 
-        if (recents.getPagedOrientationHandler() == PagedOrientationHandler.PORTRAIT) {
+        if (recents.getPagedOrientationHandler() == RecentsPagedOrientationHandler.PORTRAIT) {
             int currentRotation = recents.getPagedViewOrientedState().getRecentsActivityRotation();
             return (currentRotation - mThumbnailData.rotation) % 2 != 0;
         } else {
@@ -549,7 +548,7 @@
     }
 
     private void updateThumbnailMatrix() {
-        DeviceProfile dp = mActivity.getDeviceProfile();
+        DeviceProfile dp = mContainer.getDeviceProfile();
         mPreviewPositionHelper.setOrientationChanged(false);
         if (mBitmapShader != null && mThumbnailData != null) {
             mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 66a880b..a033243 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -20,15 +20,16 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.widget.Toast.LENGTH_SHORT;
 
-import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
 import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -37,7 +38,6 @@
 import static com.android.quickstep.TaskOverlayFactory.getEnabledShortcuts;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
 import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
-import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -54,10 +54,8 @@
 import android.graphics.Canvas;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
@@ -69,7 +67,6 @@
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
@@ -86,14 +83,15 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.TraceHelper;
@@ -107,9 +105,9 @@
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.BorderAnimator;
-import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.TaskCornerRadius;
@@ -135,10 +133,6 @@
 public class TaskView extends FrameLayout implements Reusable {
 
     private static final String TAG = TaskView.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    private static final RectF EMPTY_RECT_F = new RectF();
-
     public static final int FLAG_UPDATE_ICON = 1;
     public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
     public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
@@ -174,8 +168,6 @@
     public static final long SCALE_ICON_DURATION = 120;
     private static final long DIM_ANIM_DURATION = 700;
 
-    private static final Interpolator GRID_INTERPOLATOR = ACCELERATE_DECELERATE;
-
     /**
      * This technically can be a vanilla {@link TouchDelegate} class, however that class requires
      * setting the touch bounds at construction, so we'd repeatedly be created many instances
@@ -188,7 +180,7 @@
             Collections.singletonList(new Rect());
 
     public static final FloatProperty<TaskView> FOCUS_TRANSITION =
-            new FloatProperty<TaskView>("focusTransition") {
+            new FloatProperty<>("focusTransition") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setIconsAndBannersTransitionProgress(v, false /* invert */);
@@ -201,7 +193,7 @@
             };
 
     private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_X =
-            new FloatProperty<TaskView>("splitSelectTranslationX") {
+            new FloatProperty<>("splitSelectTranslationX") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setSplitSelectTranslationX(v);
@@ -214,7 +206,7 @@
             };
 
     private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_Y =
-            new FloatProperty<TaskView>("splitSelectTranslationY") {
+            new FloatProperty<>("splitSelectTranslationY") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setSplitSelectTranslationY(v);
@@ -227,7 +219,7 @@
             };
 
     private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
-            new FloatProperty<TaskView>("dismissTranslationX") {
+            new FloatProperty<>("dismissTranslationX") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setDismissTranslationX(v);
@@ -240,7 +232,7 @@
             };
 
     private static final FloatProperty<TaskView> DISMISS_TRANSLATION_Y =
-            new FloatProperty<TaskView>("dismissTranslationY") {
+            new FloatProperty<>("dismissTranslationY") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setDismissTranslationY(v);
@@ -253,7 +245,7 @@
             };
 
     private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_X =
-            new FloatProperty<TaskView>("taskOffsetTranslationX") {
+            new FloatProperty<>("taskOffsetTranslationX") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setTaskOffsetTranslationX(v);
@@ -266,7 +258,7 @@
             };
 
     private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_Y =
-            new FloatProperty<TaskView>("taskOffsetTranslationY") {
+            new FloatProperty<>("taskOffsetTranslationY") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setTaskOffsetTranslationY(v);
@@ -279,7 +271,7 @@
             };
 
     private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_X =
-            new FloatProperty<TaskView>("taskResistanceTranslationX") {
+            new FloatProperty<>("taskResistanceTranslationX") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setTaskResistanceTranslationX(v);
@@ -292,7 +284,7 @@
             };
 
     private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_Y =
-            new FloatProperty<TaskView>("taskResistanceTranslationY") {
+            new FloatProperty<>("taskResistanceTranslationY") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setTaskResistanceTranslationY(v);
@@ -305,7 +297,7 @@
             };
 
     public static final FloatProperty<TaskView> GRID_END_TRANSLATION_X =
-            new FloatProperty<TaskView>("gridEndTranslationX") {
+            new FloatProperty<>("gridEndTranslationX") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setGridEndTranslationX(v);
@@ -318,7 +310,7 @@
             };
 
     public static final FloatProperty<TaskView> SNAPSHOT_SCALE =
-            new FloatProperty<TaskView>("snapshotScale") {
+            new FloatProperty<>("snapshotScale") {
                 @Override
                 public void setValue(TaskView taskView, float v) {
                     taskView.setSnapshotScale(v);
@@ -341,7 +333,7 @@
     private float mNonGridScale = 1;
     private float mDismissScale = 1;
     protected final FullscreenDrawParams mCurrentFullscreenParams;
-    protected final StatefulActivity mActivity;
+    protected final RecentsViewContainer mContainer;
 
     // Various causes of changing primary translation, which we aggregate to setTranslationX/Y().
     private float mDismissTranslationX;
@@ -423,14 +415,14 @@
             int defStyleRes, BorderAnimator focusBorderAnimator,
             BorderAnimator hoverBorderAnimator) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mActivity = StatefulActivity.fromContext(context);
+        mContainer = RecentsViewContainer.containerFromContext(context);
         setOnClickListener(this::onClick);
 
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
-        mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
+        mDigitalWellBeingToast = new DigitalWellBeingToast(mContainer, this);
 
         boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
-                || isDesktopModeSupported();
+                || Flags.enableFocusOutline();
         boolean cursorHoverStatesEnabled = enableCursorHoverStates();
 
         setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled);
@@ -493,7 +485,11 @@
         return getItemInfo(mTask);
     }
 
-    protected WorkspaceItemInfo getItemInfo(@Nullable Task task) {
+    /**
+     * Builds proto for logging
+     */
+    @VisibleForTesting
+    public WorkspaceItemInfo getItemInfo(@Nullable Task task) {
         WorkspaceItemInfo stubInfo = new WorkspaceItemInfo();
         stubInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK;
         stubInfo.container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
@@ -508,6 +504,11 @@
         if (getRecentsView() != null) {
             stubInfo.screenId = getRecentsView().indexOfChild(this);
         }
+        if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+            if (UserCache.getInstance(getContext()).getUserInfo(componentKey.user).isPrivate()) {
+                stubInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+            }
+        }
         return stubInfo;
     }
 
@@ -602,10 +603,7 @@
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             computeAndSetIconTouchDelegate(mIconView, mIconCenterCoords, mIconTouchDelegate);
         }
-        if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) {
-            return true;
-        }
-        return false;
+        return mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event);
     }
 
     protected void computeAndSetIconTouchDelegate(TaskViewIcon view, float[] tempCenterCoords,
@@ -617,7 +615,7 @@
         float viewHalfHeight = view.getHeight() / 2f;
         tempCenterCoords[0] = viewHalfWidth;
         tempCenterCoords[1] = viewHalfHeight;
-        getDescendantCoordRelativeToAncestor(view.asView(), mActivity.getDragLayer(),
+        getDescendantCoordRelativeToAncestor(view.asView(), mContainer.getDragLayer(),
                 tempCenterCoords, false);
         transformingTouchDelegate.setBounds(
                 (int) (tempCenterCoords[0] - viewHalfWidth),
@@ -637,7 +635,7 @@
             return;
         }
         mModalness = modalness;
-        mIconView.setContentAlpha(1 - modalness);
+        mIconView.setModalAlpha(1 - modalness);
         mDigitalWellBeingToast.updateBannerOffset(modalness);
     }
 
@@ -647,9 +645,6 @@
 
     /**
      * Updates this task view to the given {@param task}.
-     *
-     * TODO(b/142282126) Re-evaluate if we need to pass in isMultiWindowMode after
-     *   that issue is fixed
      */
     public void bind(Task task, RecentsOrientedState orientedState) {
         cancelPendingLoadTasks();
@@ -819,13 +814,19 @@
 
     private void onClick(View view) {
         if (getTask() == null) {
+            Log.d("b/310064698", "onClick - task is null");
             return;
         }
         if (confirmSecondSplitSelectApp()) {
+            Log.d("b/310064698", mTask + " - onClick - split select is active");
             return;
         }
-        launchTasks();
-        mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
+        RunnableList callbackList = launchTasks();
+        Log.d("b/310064698", mTask + " - onClick - callbackList: " + callbackList);
+        if (callbackList != null) {
+            callbackList.add(() -> Log.d("b/310064698", mTask + " - onClick - launchCompleted"));
+        }
+        mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo())
                 .log(LAUNCHER_TASK_LAUNCH_TAP);
     }
 
@@ -840,7 +841,7 @@
             return getRecentsView().confirmSplitSelect(this, container.getTask(),
                     container.getIconView().getDrawable(), container.getThumbnailView(),
                     container.getThumbnailView().getThumbnail(), /* intent */ null,
-                    /* user */ null);
+                    /* user */ null, container.getItemInfo());
         }
         return false;
     }
@@ -863,7 +864,7 @@
         if (mTask != null) {
             TestLogging.recordEvent(
                     TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
-            ActivityOptionsWrapper opts =  mActivity.getActivityLaunchOptions(this, null);
+            ActivityOptionsWrapper opts =  mContainer.getActivityLaunchOptions(this, null);
             opts.options.setLaunchDisplayId(
                     getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (ActivityManagerWrapper.getInstance()
@@ -912,13 +913,13 @@
             TestLogging.recordEvent(
                     TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
 
-            final TaskRemovedDuringLaunchListener
-                    failureListener = new TaskRemovedDuringLaunchListener();
+            TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
+                    getContext().getApplicationContext());
             if (isQuickswitch) {
                 // We only listen for failures to launch in quickswitch because the during this
                 // gesture launcher is in the background state, vs other launches which are in
                 // the actual overview state
-                failureListener.register(mActivity, mTask.key.id, () -> {
+                failureListener.register(mContainer, mTask.key.id, () -> {
                     notifyTaskLaunchFailed(TAG);
                     RecentsView rv = getRecentsView();
                     if (rv != null) {
@@ -940,12 +941,8 @@
             // Indicate success once the system has indicated that the transition has started
             ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
                     MAIN_EXECUTOR.getHandler(),
-                    elapsedRealTime -> {
-                        callback.accept(true);
-                    },
-                    elapsedRealTime -> {
-                        failureListener.onTransitionFinished();
-                    });
+                    elapsedRealTime -> callback.accept(true),
+                    elapsedRealTime -> failureListener.onTransitionFinished());
             opts.setLaunchDisplayId(
                     getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (isQuickswitch) {
@@ -970,20 +967,6 @@
     }
 
     /**
-     * Returns ActivityOptions for overriding task transition animation.
-     */
-    private ActivityOptions makeCustomAnimation(Context context, int enterResId,
-            int exitResId, final Runnable callback, final Handler callbackHandler) {
-        return ActivityOptions.makeCustomTaskAnimation(context, enterResId, exitResId,
-                callbackHandler,
-                elapsedRealTime -> {
-                    if (callback != null) {
-                        callbackHandler.post(callback);
-                    }
-                }, null /* finishedListener */);
-    }
-
-    /**
      * Launch of the current task (both live and inactive tasks) with an animation.
      */
     @Nullable
@@ -1030,19 +1013,10 @@
             TaskViewUtils.composeRecentsLaunchAnimator(
                     anim, this, targets.apps,
                     targets.wallpapers, targets.nonApps, true /* launcherClosing */,
-                    mActivity.getStateManager(), recentsView,
+                    recentsView.getStateManager(), recentsView,
                     recentsView.getDepthController());
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
-                public void onAnimationStart(Animator animation) {
-                    recentsView.runActionOnRemoteHandles(
-                            (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
-                                    remoteTargetHandle
-                                            .getTaskViewSimulator()
-                                            .setDrawsBelowRecents(false));
-                }
-
-                @Override
                 public void onAnimationEnd(Animator animator) {
                     if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
                         launchTaskAnimated();
@@ -1148,12 +1122,12 @@
             return true;
         }
 
-        if (!mActivity.getDeviceProfile().isTablet
+        if (!mContainer.getDeviceProfile().isTablet
                 && !getRecentsView().isClearAllHidden()) {
             getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
             return false;
         } else {
-            mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
+            mContainer.getStatsLogManager().logger().withItemInfo(getItemInfo())
                     .log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS);
             return showTaskMenuWithContainer(iconView);
         }
@@ -1162,12 +1136,11 @@
     protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
         TaskIdAttributeContainer menuContainer =
                 mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1];
-        DeviceProfile dp = mActivity.getDeviceProfile();
+        DeviceProfile dp = mContainer.getDeviceProfile();
         if (enableOverviewIconMenu() && iconView instanceof IconAppChipView) {
             ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ true);
-            return TaskMenuView.showForTask(menuContainer, () -> {
-                ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false);
-            });
+            return TaskMenuView.showForTask(menuContainer,
+                    () -> ((IconAppChipView) iconView).revealAnim(/* isRevealing= */ false));
         } else if (dp.isTablet) {
             int alignedOptionIndex = 0;
             if (getRecentsView().isOnGridBottomRow(menuContainer.getTaskView()) && dp.isLandscape) {
@@ -1217,7 +1190,7 @@
     }
 
     protected void setThumbnailOrientation(RecentsOrientedState orientationState) {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
 
         // TODO(b/271468547), we should default to setting trasnlations only on the snapshot instead
@@ -1234,7 +1207,7 @@
      * Returns whether the task is part of overview grid and not being focused.
      */
     public boolean isGridTask() {
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
         return deviceProfile.isTablet && !isFocusedTask();
     }
 
@@ -1341,17 +1314,15 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (mActivity.getDeviceProfile().isTablet) {
+        if (mContainer.getDeviceProfile().isTablet) {
             setPivotX(getLayoutDirection() == LAYOUT_DIRECTION_RTL ? 0 : right - left);
             setPivotY(mSnapshotView.getTop());
         } else {
             setPivotX((right - left) * 0.5f);
             setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f);
         }
-        if (Utilities.ATLEAST_Q) {
-            SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
-            setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
-        }
+        SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight());
+        setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
     }
 
     /**
@@ -1403,8 +1374,7 @@
      */
     public float getPersistentScale() {
         float scale = 1;
-        float gridProgress = GRID_INTERPOLATOR.getInterpolation(mGridProgress);
-        scale *= Utilities.mapRange(gridProgress, mNonGridScale, 1f);
+        scale *= Utilities.mapRange(mGridProgress, mNonGridScale, 1f);
         return scale;
     }
 
@@ -1610,19 +1580,6 @@
         mEndQuickswitchCuj = endQuickswitchCuj;
     }
 
-    private int getExpectedViewHeight(View view) {
-        int expectedHeight;
-        int h = view.getLayoutParams().height;
-        if (h > 0) {
-            expectedHeight = h;
-        } else {
-            int m = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY - 1, MeasureSpec.AT_MOST);
-            view.measure(m, m);
-            expectedHeight = view.getMeasuredHeight();
-        }
-        return expectedHeight;
-    }
-
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
@@ -1691,7 +1648,7 @@
         return (RecentsView) getParent();
     }
 
-    PagedOrientationHandler getPagedOrientationHandler() {
+    RecentsPagedOrientationHandler getPagedOrientationHandler() {
         return getRecentsView().mOrientationState.getOrientationHandler();
     }
 
@@ -1714,10 +1671,10 @@
         mFullscreenProgress = progress;
         mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
         mSnapshotView.getTaskOverlay().setFullscreenProgress(progress);
-
+        RecentsView recentsView = mContainer.getOverviewPanel();
         // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
         // oversized and banner would look disproportionately large.
-        if (mActivity.getStateManager().getState() != BACKGROUND_APP) {
+        if (recentsView.getStateManager().getState() != BACKGROUND_APP) {
             setIconsAndBannersTransitionProgress(progress, true);
         }
 
@@ -1751,22 +1708,16 @@
         float boxTranslationY;
         int expectedWidth;
         int expectedHeight;
-        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        DeviceProfile deviceProfile = mContainer.getDeviceProfile();
+        final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
+        final int taskWidth = lastComputedTaskSize.width();
+        final int taskHeight = lastComputedTaskSize.height();
         if (deviceProfile.isTablet) {
-            final int thumbnailPadding = deviceProfile.overviewTaskThumbnailTopMarginPx;
-            final Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
-            final int taskWidth = lastComputedTaskSize.width();
-            final int taskHeight = lastComputedTaskSize.height();
-
             int boxWidth;
             int boxHeight;
             boolean isFocusedTask = isFocusedTask();
-            if (isDesktopTask()) {
-                Rect lastComputedDesktopTaskSize =
-                        getRecentsView().getLastComputedDesktopTaskSize();
-                boxWidth = lastComputedDesktopTaskSize.width();
-                boxHeight = lastComputedDesktopTaskSize.height();
-            } else if (isFocusedTask) {
+            if (isFocusedTask) {
                 // Task will be focused and should use focused task size. Use focusTaskRatio
                 // that is associated with the original orientation of the focused task.
                 boxWidth = taskWidth;
@@ -1783,15 +1734,23 @@
             expectedHeight = boxHeight + thumbnailPadding;
 
             // Scale to to fit task Rect.
-            nonGridScale = taskWidth / (float) boxWidth;
+            if (enableGridOnlyOverview()) {
+                final Rect lastComputedCarouselTaskSize =
+                        getRecentsView().getLastComputedCarouselTaskSize();
+                nonGridScale = lastComputedCarouselTaskSize.width() / (float) taskWidth;
+            } else {
+                nonGridScale = taskWidth / (float) boxWidth;
+            }
 
             // Align to top of task Rect.
             boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
         } else {
             nonGridScale = 1f;
             boxTranslationY = 0f;
-            expectedWidth = ViewGroup.LayoutParams.MATCH_PARENT;
-            expectedHeight = ViewGroup.LayoutParams.MATCH_PARENT;
+            expectedWidth = enableOverviewIconMenu() ? taskWidth : LayoutParams.MATCH_PARENT;
+            expectedHeight = enableOverviewIconMenu()
+                    ? taskHeight + thumbnailPadding
+                    : LayoutParams.MATCH_PARENT;
         }
 
         setNonGridScale(nonGridScale);
@@ -1804,8 +1763,7 @@
     }
 
     private float getGridTrans(float endTranslation) {
-        float progress = GRID_INTERPOLATOR.getInterpolation(mGridProgress);
-        return Utilities.mapRange(progress, 0, endTranslation);
+        return Utilities.mapRange(mGridProgress, 0, endTranslation);
     }
 
     private float getNonGridTrans(float endTranslation) {
@@ -1879,7 +1837,7 @@
     /**
      * We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
      */
-    public static class FullscreenDrawParams {
+    public static class FullscreenDrawParams implements SafeCloseable {
 
         private float mCornerRadius;
         private float mWindowCornerRadius;
@@ -1914,6 +1872,9 @@
                     Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
                             / parentScale / taskViewScale;
         }
+
+        @Override
+        public void close() { }
     }
 
     public class TaskIdAttributeContainer {
diff --git a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
index 4e82725..94739cb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
+++ b/quickstep/src/com/android/quickstep/views/TaskViewIcon.java
@@ -43,6 +43,11 @@
     void setContentAlpha(float alpha);
 
     /**
+     * Sets the opacity of the view for modal state.
+     */
+    void setModalAlpha(float alpha);
+
+    /**
      * Returns this icon view's drawable.
      */
     @Nullable Drawable getDrawable();
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
new file mode 100644
index 0000000..d4dd580
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.app.prediction.AppTarget;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Process;
+import android.os.UserHandle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.UserIconInfo;
+import com.android.systemui.shared.system.SysUiStatsLog;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppEventProducerTest {
+
+    private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
+    private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+
+    private static final UserIconInfo MAIN_ICON_INFO =
+            new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
+    private static final UserIconInfo PRIVATE_ICON_INFO =
+            new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
+
+    private SandboxContext mContext;
+    private AppEventProducer mAppEventProducer;
+    @Mock
+    private UserCache mUserCache;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = new SandboxContext(getApplicationContext());
+        mContext.putObject(UserCache.INSTANCE, mUserCache);
+        mAppEventProducer = new AppEventProducer(mContext, null);
+    }
+
+    @After
+    public void tearDown() {
+        mContext.onDestroy();
+    }
+
+    @Test
+    public void buildAppTarget_containsCorrectUser() {
+        when(mUserCache.getUserProfiles())
+                .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
+        when(mUserCache.getUserInfo(any(UserHandle.class)))
+                .thenReturn(MAIN_ICON_INFO, PRIVATE_ICON_INFO);
+        ComponentName gmailComponentName = new ComponentName(mContext,
+                "com.android.launcher3.tests.Activity" + "Gmail");
+        AppInfo gmailAppInfo = new
+                AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
+        gmailAppInfo.container = CONTAINER_ALL_APPS;
+        gmailAppInfo.itemType = ITEM_TYPE_APPLICATION;
+
+        AppTarget gmailTarget = mAppEventProducer
+                .toAppTarget(buildItemInfoProtoForAppInfo(gmailAppInfo));
+
+        assert gmailTarget != null;
+        assertEquals(gmailTarget.getUser(), MAIN_HANDLE);
+
+        when(mUserCache.getUserInfo(any(UserHandle.class)))
+                .thenReturn(MAIN_ICON_INFO, PRIVATE_ICON_INFO);
+        AppInfo gmailAppInfoPrivate = new
+                AppInfo(gmailComponentName, "Gmail", PRIVATE_HANDLE, new Intent());
+        gmailAppInfoPrivate.container = CONTAINER_ALL_APPS;
+        gmailAppInfoPrivate.itemType = ITEM_TYPE_APPLICATION;
+
+        AppTarget gmailPrivateTarget = mAppEventProducer
+                .toAppTarget(buildItemInfoProtoForAppInfo(gmailAppInfoPrivate));
+
+        assert gmailPrivateTarget != null;
+        assertEquals(gmailPrivateTarget.getUser(), PRIVATE_HANDLE);
+    }
+
+    private LauncherAtom.ItemInfo buildItemInfoProtoForAppInfo(AppInfo appInfo) {
+        LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
+        if (appInfo.user.equals(PRIVATE_HANDLE)) {
+            itemBuilder.setUserType(SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_PRIVATE);
+        } else {
+            itemBuilder.setUserType(SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_MAIN);
+        }
+        itemBuilder.setApplication(LauncherAtom.Application.newBuilder()
+                .setComponentName(appInfo.componentName.flattenToShortString())
+                .setPackageName(appInfo.componentName.getPackageName()));
+        itemBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
+                .setAllAppsContainer(LauncherAtom.AllAppsContainer.getDefaultInstance())
+                .build());
+        return itemBuilder.build();
+    }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
new file mode 100644
index 0000000..d90e048
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.animation
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.Path
+import android.graphics.drawable.ColorDrawable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.INVISIBLE
+import android.view.View.VISIBLE
+import android.widget.FrameLayout
+import androidx.core.graphics.drawable.toBitmap
+import androidx.dynamicanimation.animation.DynamicAnimation
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
+import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
+import com.android.launcher3.taskbar.bubbles.BubbleBarView
+import com.android.launcher3.taskbar.bubbles.BubbleStashController
+import com.android.launcher3.taskbar.bubbles.BubbleView
+import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.animation.PhysicsAnimator
+import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubbleBarViewAnimatorTest {
+
+    private val context = ApplicationProvider.getApplicationContext<Context>()
+    private val animatorScheduler = TestBubbleBarViewAnimatorScheduler()
+
+    @Before
+    fun setUp() {
+        PhysicsAnimatorTestUtils.prepareForTest()
+    }
+
+    @Test
+    fun animateBubbleInForStashed() {
+        lateinit var overflowView: BubbleView
+        lateinit var bubbleView: BubbleView
+        lateinit var bubble: BubbleBarBubble
+        val bubbleBarView = BubbleBarView(context)
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
+            val inflater = LayoutInflater.from(context)
+
+            val bitmap = ColorDrawable(Color.WHITE).toBitmap(width = 20, height = 20)
+            overflowView =
+                inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
+            overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
+            bubbleBarView.addView(overflowView)
+
+            val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false)
+            bubbleView =
+                inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
+            bubble =
+                BubbleBarBubble(bubbleInfo, bubbleView, bitmap, bitmap, Color.WHITE, Path(), "")
+            bubbleView.setBubble(bubble)
+            bubbleBarView.addView(bubbleView)
+        }
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+        val bubbleStashController = mock<BubbleStashController>()
+        whenever(bubbleStashController.isStashed).thenReturn(true)
+
+        val handle = View(context)
+        val handleAnimator = PhysicsAnimator.getInstance(handle)
+        whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
+
+        val animator =
+            BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            animator.animateBubbleInForStashed(bubble)
+        }
+
+        // let the animation start and wait for it to complete
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(handle.alpha).isEqualTo(0)
+        assertThat(handle.translationY).isEqualTo(-70)
+        assertThat(overflowView.visibility).isEqualTo(INVISIBLE)
+        assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleView.alpha).isEqualTo(1)
+        assertThat(bubbleView.translationY).isEqualTo(-20)
+        assertThat(bubbleView.scaleY).isEqualTo(1)
+
+        // execute the hide bubble animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
+
+        // let the animation start and wait for it to complete
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+
+        assertThat(bubbleView.alpha).isEqualTo(1)
+        assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
+        assertThat(bubbleView.translationY).isEqualTo(0)
+        assertThat(bubbleBarView.alpha).isEqualTo(0)
+        assertThat(overflowView.alpha).isEqualTo(1)
+        assertThat(overflowView.visibility).isEqualTo(VISIBLE)
+        assertThat(handle.alpha).isEqualTo(1)
+        assertThat(handle.translationY).isEqualTo(0)
+    }
+
+    private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler {
+
+        var delayedBlock: (() -> Unit)? = null
+            private set
+
+        override fun post(block: () -> Unit) {
+            block.invoke()
+        }
+
+        override fun postDelayed(delayMillis: Long, block: () -> Unit) {
+            check(delayedBlock == null) { "there is already a pending block waiting to run" }
+            delayedBlock = block
+        }
+    }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
similarity index 81%
rename from quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 9c7f014..c327166 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -1,19 +1,22 @@
 package com.android.launcher3.taskbar.navbutton
 
+import android.content.res.Configuration
 import android.content.res.Resources
 import android.view.Surface
 import android.view.Surface.ROTATION_270
 import android.view.Surface.Rotation
 import android.view.View
 import android.view.ViewGroup
-import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
+import android.widget.Space
 import androidx.test.runner.AndroidJUnit4
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
-import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
 import com.android.systemui.shared.rotation.RotationButton
 import java.lang.IllegalStateException
 import org.junit.Assume.assumeTrue
@@ -27,7 +30,7 @@
 class NavButtonLayoutFactoryTest {
 
     private val mockDeviceProfile: DeviceProfile = mock()
-    private val mockParentButtonContainer: FrameLayout = mock()
+    private val mockParentButtonContainer: NearestTouchFrame = mock()
     private val mockNavLayout: LinearLayout = mock()
     private val mockStartContextualLayout: ViewGroup = mock()
     private val mockEndContextualLayout: ViewGroup = mock()
@@ -38,6 +41,8 @@
     private val mockImeSwitcher: ImageView = mock()
     private val mockRotationButton: RotationButton = mock()
     private val mockA11yButton: ImageView = mock()
+    private val mockSpace: Space = mock()
+    private val mockConfiguration: Configuration = mock();
 
     private var surfaceRotation = Surface.ROTATION_0
 
@@ -50,12 +55,15 @@
         whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
 
         // Init top level layout
-        whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
+        whenever(mockParentButtonContainer.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS))
             .thenReturn(mockNavLayout)
-        whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
+        whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS))
             .thenReturn(mockEndContextualLayout)
-        whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
+        whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS))
             .thenReturn(mockStartContextualLayout)
+        whenever(mockBackButton.resources).thenReturn(mockResources)
+        whenever(mockResources.configuration).thenReturn(mockConfiguration)
+        whenever(mockConfiguration.layoutDirection).thenReturn(0)
     }
 
     @Test
@@ -163,17 +171,19 @@
         assert(layoutter is PhoneSeascapeNavLayoutter)
     }
 
-    @Test(expected = IllegalStateException::class)
-    fun noValidLayoutForPhoneGestureNav() {
+    @Test
+    fun getTaskbarPhoneGestureNavLayoutter() {
         assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
         mockDeviceProfile.isTaskbarPresent = false
-        getLayoutter(
-            isKidsMode = false,
-            isInSetup = false,
-            isThreeButtonNav = false,
-            phoneMode = true,
-            surfaceRotation = surfaceRotation
-        )
+        val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
+            getLayoutter(
+                isKidsMode = false,
+                isInSetup = false,
+                isThreeButtonNav = false,
+                phoneMode = true,
+                surfaceRotation = surfaceRotation
+            )
+        assert(layoutter is PhoneGestureLayoutter)
     }
 
     private fun setDeviceProfileLandscape() {
@@ -201,7 +211,8 @@
             surfaceRotation = surfaceRotation,
             imeSwitcher = mockImeSwitcher,
             rotationButton = mockRotationButton,
-            a11yButton = mockA11yButton
+            a11yButton = mockA11yButton,
+            space = mockSpace,
         )
     }
 }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
new file mode 100644
index 0000000..73b35e8
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.app.PendingIntent
+import android.content.IIntentSender
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit.SECONDS
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TIMEOUT = 5L
+
+@RunWith(AndroidJUnit4::class)
+class AllAppsActionManagerTest {
+    private val callbackSemaphore = Semaphore(0)
+    private val bgExecutor = UI_HELPER_EXECUTOR
+
+    private val allAppsActionManager =
+        AllAppsActionManager(
+            InstrumentationRegistry.getInstrumentation().targetContext,
+            bgExecutor,
+        ) {
+            callbackSemaphore.release()
+            PendingIntent(IIntentSender.Default())
+        }
+
+    @Test
+    fun taskbarPresent_actionRegistered() {
+        allAppsActionManager.isTaskbarPresent = true
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isTrue()
+    }
+
+    @Test
+    fun homeAndOverviewSame_actionRegistered() {
+        allAppsActionManager.isHomeAndOverviewSame = true
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isTrue()
+    }
+
+    @Test
+    fun toggleTaskbar_destroyedAfterActionRegistered_actionUnregistered() {
+        allAppsActionManager.isTaskbarPresent = true
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+        allAppsActionManager.isTaskbarPresent = false
+        TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+        assertThat(allAppsActionManager.isActionRegistered).isFalse()
+    }
+
+    @Test
+    fun toggleTaskbar_destroyedBeforeActionRegistered_pendingActionUnregistered() {
+        allAppsActionManager.isTaskbarPresent = true
+        allAppsActionManager.isTaskbarPresent = false
+
+        TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isFalse()
+    }
+
+    @Test
+    fun changeHome_sameAsOverviewBeforeActionUnregistered_actionRegisteredAgain() {
+        allAppsActionManager.isHomeAndOverviewSame = true // Initialize to same.
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+        allAppsActionManager.isHomeAndOverviewSame = false
+        allAppsActionManager.isHomeAndOverviewSame = true
+        assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+        assertThat(allAppsActionManager.isActionRegistered).isTrue()
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/NavigationBarRotationContextTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/NavigationBarRotationContextTest.java
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/RobolectricTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/RobolectricTest.kt
new file mode 100644
index 0000000..0694aec
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/RobolectricTest.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RobolectricTest {
+    @Test
+    fun test1() {
+        val actual = 1 + 1
+        assertThat(actual).isEqualTo(2)
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
new file mode 100644
index 0000000..ea52842
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.orientation
+
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
+import com.android.quickstep.orientation.LandscapePagedViewHandler.SplitIconPositions
+import com.android.quickstep.views.IconAppChipView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class LandscapePagedViewHandlerTest {
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private val sut = LandscapePagedViewHandler()
+
+    private fun enableGridOnlyOverview(isEnabled: Boolean) {
+        if (isEnabled) {
+            setFlagsRule.enableFlags(
+                Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+            )
+        } else {
+            setFlagsRule.disableFlags(
+                Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+            )
+        }
+    }
+
+    /** [ Test getSplitIconsPosition ] */
+    private fun getSplitIconsPosition(isRTL: Boolean): SplitIconPositions {
+        return sut.getSplitIconsPosition(
+            TASK_ICON_HEIGHT_PX,
+            PRIMARY_SNAPSHOT,
+            TOTAL_THUMBNAIL_HEIGHT,
+            isRTL,
+            OVERVIEW_TASK_MARGIN_PX,
+            DIVIDER_SIZE_PX,
+        )
+    }
+
+    @Test
+    fun testIcon_getSplitIconsPositions() {
+        enableGridOnlyOverview(false)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+        // Top-Left icon should be at the end of the primary snapshot height
+        assertThat(topLeftY).isEqualTo(250)
+        // Bottom-Right icon should be at the end of the primary height + divider + icon size
+        assertThat(bottomRightY).isEqualTo(374)
+    }
+
+    @Test
+    fun testIcon_getSplitIconsPositions_isRTL() {
+        enableGridOnlyOverview(false)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+        // Top-Left icon should be at the end of the primary snapshot height
+        assertThat(topLeftY).isEqualTo(250)
+        // Bottom-Right icon should be at the end of the primary height + divider + icon size
+        assertThat(bottomRightY).isEqualTo(374)
+    }
+
+    @Test
+    fun testChip_getSplitIconsPositions() {
+        enableGridOnlyOverview(true)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+        // Top-Left app chip should always be at the initial position of the first snapshot
+        assertThat(topLeftY).isEqualTo(0)
+        // Bottom-Right app chip should be at the end of the primary height + divider
+        assertThat(bottomRightY).isEqualTo(266)
+    }
+
+    @Test
+    fun testChip_getSplitIconsPositions_isRTL() {
+        enableGridOnlyOverview(true)
+
+        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)
+    }
+
+    /** Test updateSplitIconsPosition */
+    @Test
+    fun testIcon_updateSplitIconsPosition() {
+        enableGridOnlyOverview(false)
+
+        val expectedTranslationY = 250
+        val expectedGravity = Gravity.TOP or Gravity.RIGHT
+
+        val iconView = mock<View>()
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+        assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+        assertThat(frameLayout.topMargin).isEqualTo(expectedTranslationY)
+        verify(iconView).translationX = 0f
+        verify(iconView).translationY = 0f
+    }
+
+    @Test
+    fun testIcon_updateSplitIconsPosition_isRTL() {
+        enableGridOnlyOverview(false)
+
+        val expectedTranslationY = 250
+        val expectedGravity = Gravity.TOP or Gravity.RIGHT
+
+        val iconView = mock<View>()
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+        assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+        assertThat(frameLayout.topMargin).isEqualTo(expectedTranslationY)
+        verify(iconView).translationX = 0f
+        verify(iconView).translationY = 0f
+    }
+
+    @Test
+    fun testChip_updateSplitIconsPosition() {
+        enableGridOnlyOverview(true)
+
+        val expectedTranslationY = 250
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        val iconView = mock<IconAppChipView>()
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END)
+        verify(iconView).setSplitTranslationX(0f)
+        verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+    }
+
+    @Test
+    fun testChip_updateSplitIconsPosition_isRTL() {
+        enableGridOnlyOverview(true)
+
+        val expectedTranslationY = 250
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        val iconView = mock<IconAppChipView>()
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START)
+        verify(iconView).setSplitTranslationX(0f)
+        verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+    }
+
+    private companion object {
+        const val TASK_ICON_HEIGHT_PX = 108
+        const val OVERVIEW_TASK_MARGIN_PX = 0
+        const val DIVIDER_SIZE_PX = 16
+        const val PRIMARY_SNAPSHOT = 250
+        const val SECONDARY_SNAPSHOT = 300
+        const val TOTAL_THUMBNAIL_HEIGHT = PRIMARY_SNAPSHOT + SECONDARY_SNAPSHOT + DIVIDER_SIZE_PX
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
new file mode 100644
index 0000000..2bc182c
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.orientation
+
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
+import com.android.quickstep.orientation.LandscapePagedViewHandler.SplitIconPositions
+import com.android.quickstep.views.IconAppChipView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class SeascapePagedViewHandlerTest {
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private val sut = SeascapePagedViewHandler()
+
+    private fun enableGridOnlyOverview(isEnabled: Boolean) {
+        if (isEnabled) {
+            setFlagsRule.enableFlags(
+                Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+            )
+        } else {
+            setFlagsRule.disableFlags(
+                Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+                Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+            )
+        }
+    }
+
+    /** [ Test getSplitIconsPosition ] */
+    private fun getSplitIconsPosition(isRTL: Boolean): SplitIconPositions {
+        return sut.getSplitIconsPosition(
+            TASK_ICON_HEIGHT_PX,
+            PRIMARY_SNAPSHOT,
+            TOTAL_THUMBNAIL_HEIGHT,
+            isRTL,
+            OVERVIEW_TASK_MARGIN_PX,
+            DIVIDER_SIZE_PX,
+        )
+    }
+
+    @Test
+    fun testIcon_getSplitIconsPositions() {
+        enableGridOnlyOverview(false)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+        // The top-left icon is translated from the bottom of the screen to the end of
+        // the primary snapshot minus the icon size.
+        assertThat(topLeftY).isEqualTo(142)
+        // The bottom-right icon is placed at the end of the primary snapshot plus the divider.
+        assertThat(bottomRightY).isEqualTo(266)
+    }
+
+    @Test
+    fun testIcon_getSplitIconsPositions_isRTL() {
+        enableGridOnlyOverview(false)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+        // The top-left icon is translated from the bottom of the screen to the end of
+        // the primary snapshot minus the icon size.
+        assertThat(topLeftY).isEqualTo(142)
+        // The bottom-right icon is placed at the end of the primary snapshot plus the divider.
+        assertThat(bottomRightY).isEqualTo(266)
+    }
+
+    @Test
+    fun testChip_getSplitIconsPositions() {
+        enableGridOnlyOverview(true)
+
+        val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+        // Top-Left app chip should always be at the initial position of the first snapshot
+        assertThat(topLeftY).isEqualTo(0)
+        // Bottom-Right app chip should be at the end of the primary height + divider
+        assertThat(bottomRightY).isEqualTo(-266)
+    }
+
+    @Test
+    fun testChip_getSplitIconsPositions_isRTL() {
+        enableGridOnlyOverview(true)
+
+        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)
+    }
+
+    /** Test updateSplitIconsPosition */
+    @Test
+    fun testIcon_updateSplitIconsPosition() {
+        enableGridOnlyOverview(false)
+
+        val expectedTranslationY = 250
+        val expectedGravity = Gravity.BOTTOM or Gravity.LEFT
+
+        val iconView = mock<View>()
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+        assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+        assertThat(frameLayout.bottomMargin).isEqualTo(expectedTranslationY)
+        verify(iconView).translationX = 0f
+        verify(iconView).translationY = 0f
+    }
+
+    @Test
+    fun testIcon_updateSplitIconsPosition_isRTL() {
+        enableGridOnlyOverview(false)
+
+        val expectedTranslationY = 250
+        val expectedGravity = Gravity.BOTTOM or Gravity.LEFT
+
+        val iconView = mock<View>()
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+        assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+        assertThat(frameLayout.bottomMargin).isEqualTo(expectedTranslationY)
+        verify(iconView).translationX = 0f
+        verify(iconView).translationY = 0f
+    }
+
+    @Test
+    fun testChip_updateSplitIconsPosition() {
+        enableGridOnlyOverview(true)
+
+        val expectedTranslationY = 250
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        val iconView = mock<IconAppChipView>()
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START)
+        verify(iconView).setSplitTranslationX(0f)
+        verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+    }
+
+    @Test
+    fun testChip_updateSplitIconsPosition_isRTL() {
+        enableGridOnlyOverview(true)
+
+        val expectedTranslationY = 250
+        val frameLayout = FrameLayout.LayoutParams(100, 100)
+        val iconView = mock<IconAppChipView>()
+        `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+        sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+        assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END)
+        verify(iconView).setSplitTranslationX(0f)
+        verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+    }
+
+    private companion object {
+        const val TASK_ICON_HEIGHT_PX = 108
+        const val OVERVIEW_TASK_MARGIN_PX = 0
+        const val DIVIDER_SIZE_PX = 16
+        const val PRIMARY_SNAPSHOT = 250
+        const val SECONDARY_SNAPSHOT = 300
+        const val TOTAL_THUMBNAIL_HEIGHT = PRIMARY_SNAPSHOT + SECONDARY_SNAPSHOT + DIVIDER_SIZE_PX
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
similarity index 92%
rename from quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index f41ac48..0de5f19 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -27,6 +27,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.launcher3.LauncherState
 import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.StatsLogger
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.statehandlers.DepthController
 import com.android.launcher3.statemanager.StateManager
@@ -35,6 +36,8 @@
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.util.SplitSelectStateController.SplitFromDesktopController
+import com.android.quickstep.views.RecentsViewContainer
 import com.android.systemui.shared.recents.model.Task
 import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
 import java.util.function.Consumer
@@ -45,6 +48,8 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.Mockito.any
+import org.mockito.Mockito.`when`
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
@@ -56,13 +61,15 @@
     private val systemUiProxy: SystemUiProxy = mock()
     private val depthController: DepthController = mock()
     private val statsLogManager: StatsLogManager = mock()
+    private val statsLogger: StatsLogger = mock()
     private val stateManager: StateManager<LauncherState> = mock()
     private val handler: Handler = mock()
-    private val context: StatefulActivity<*> = mock()
+    private val context: RecentsViewContainer = mock()
     private val recentsModel: RecentsModel = mock()
     private val pendingIntent: PendingIntent = mock()
+    private val splitFromDesktopController: SplitFromDesktopController = mock()
 
-    lateinit var splitSelectStateController: SplitSelectStateController
+    private lateinit var splitSelectStateController: SplitSelectStateController
 
     private val primaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId)
     private val nonPrimaryUserHandle = UserHandle(ActivityManager.RunningTaskInfo().userId + 10)
@@ -74,6 +81,9 @@
 
     @Before
     fun setup() {
+        `when`(statsLogManager.logger()).thenReturn(statsLogger)
+        `when`(statsLogger.withInstanceId(any())).thenReturn(statsLogger)
+        `when`(statsLogger.withItemInfo(any())).thenReturn(statsLogger)
         splitSelectStateController =
             SplitSelectStateController(
                 context,
@@ -107,7 +117,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
+            Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
 
         // Capture callback from recentsModel#getTasks()
         val consumer =
@@ -148,7 +158,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals(
                     "ComponentName package mismatched",
                     it[0].key.baseIntent.component?.packageName,
@@ -201,7 +211,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
+            Consumer<Array<Task>> { assertNull("No tasks should have matched", it[0] /*task*/) }
 
         // Capture callback from recentsModel#getTasks()
         val consumer =
@@ -244,7 +254,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals(
                     "ComponentName package mismatched",
                     it[0].key.baseIntent.component?.packageName,
@@ -298,7 +308,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals(
                     "ComponentName package mismatched",
                     it[0].key.baseIntent.component?.packageName,
@@ -350,7 +360,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals("Expected array length 2", 2, it.size)
                 assertNull("No tasks should have matched", it[0] /*task*/)
                 assertEquals(
@@ -403,7 +413,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals("Expected array length 2", 2, it.size)
                 assertEquals(
                     "ComponentName package mismatched",
@@ -459,7 +469,7 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
+            Consumer<Array<Task>> {
                 assertEquals("Expected array length 2", 2, it.size)
                 assertEquals(
                     "ComponentName package mismatched",
@@ -532,8 +542,8 @@
         // Assertions happen in the callback we get from what we pass into
         // #findLastActiveTasksAndRunCallback
         val taskConsumer =
-            Consumer<List<Task>> {
-                assertEquals("Expected array length 1", 1, it.size)
+            Consumer<Array<Task>> {
+                assertEquals("Expected array length 2", 2, it.size)
                 assertEquals("Found wrong task", it[0], groupTask2.task1)
             }
 
@@ -593,12 +603,25 @@
     @Test
     fun secondPendingIntentSet() {
         val itemInfo = ItemInfo()
+        val itemInfo2 = ItemInfo()
         whenever(pendingIntent.creatorUserHandle).thenReturn(primaryUserHandle)
         splitSelectStateController.setInitialTaskSelect(null, 0, itemInfo, null, 1)
-        splitSelectStateController.setSecondTask(pendingIntent)
+        splitSelectStateController.setSecondTask(pendingIntent, itemInfo2)
         assertTrue(splitSelectStateController.isBothSplitAppsConfirmed)
     }
 
+    @Test
+    fun splitSelectStateControllerDestroyed_SplitFromDesktopControllerAlsoDestroyed() {
+        // Initiate split from desktop controller
+        splitSelectStateController.initSplitFromDesktopController(splitFromDesktopController)
+
+        // Simulate default controller being destroyed
+        splitSelectStateController.onDestroy()
+
+        // Verify desktop controller is also destroyed
+        verify(splitFromDesktopController).onDestroy()
+    }
+
     // Generate GroupTask with default userId.
     private fun generateGroupTask(
         task1ComponentName: ComponentName,
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskGridNavHelperTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
similarity index 96%
rename from quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index b365173..72cfd92 100644
--- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.util.window.CachedDisplayInfo;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.SurfaceTransaction.MockProperties;
 
 import org.hamcrest.Description;
@@ -160,11 +159,9 @@
         void verifyNoTransforms() {
             LauncherModelHelper helper = new LauncherModelHelper();
             try {
-                helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
                 int rotation = mDisplaySize.x > mDisplaySize.y
                         ? Surface.ROTATION_90 : Surface.ROTATION_0;
-                CachedDisplayInfo cdi =
-                        new CachedDisplayInfo(mDisplaySize, rotation, new Rect());
+                CachedDisplayInfo cdi = new CachedDisplayInfo(mDisplaySize, rotation);
                 WindowBounds wm = new WindowBounds(
                         new Rect(0, 0, mDisplaySize.x, mDisplaySize.y),
                         mDisplayInsets);
@@ -186,7 +183,7 @@
 
                 ArrayMap<CachedDisplayInfo, List<WindowBounds>> perDisplayBoundsCache =
                         new ArrayMap<>();
-                perDisplayBoundsCache.put(cdi.normalize(), allBounds);
+                perDisplayBoundsCache.put(cdi.normalize(wmProxy), allBounds);
 
                 Configuration configuration = new Configuration();
                 configuration.densityDpi = mDensityDpi;
diff --git a/quickstep/tests/multivalentTestsForDevice b/quickstep/tests/multivalentTestsForDevice
new file mode 120000
index 0000000..fa0fabf
--- /dev/null
+++ b/quickstep/tests/multivalentTestsForDevice
@@ -0,0 +1 @@
+./multivalentTests
\ No newline at end of file
diff --git a/quickstep/tests/multivalentTestsForDeviceless b/quickstep/tests/multivalentTestsForDeviceless
new file mode 120000
index 0000000..fa0fabf
--- /dev/null
+++ b/quickstep/tests/multivalentTestsForDeviceless
@@ -0,0 +1 @@
+./multivalentTests
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
index b12d98b..8702f70 100644
--- a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
+++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.model;
 
+import static android.content.pm.ApplicationInfo.CATEGORY_PRODUCTIVITY;
+import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
 import static android.os.Process.myUserHandle;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
@@ -26,6 +28,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
@@ -35,12 +39,17 @@
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
 import android.os.UserHandle;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.text.TextUtils;
 
+import androidx.test.core.content.pm.ApplicationInfoBuilder;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
 import com.android.launcher3.util.LauncherLayoutBuilder;
@@ -50,6 +59,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -61,6 +71,9 @@
 @RunWith(AndroidJUnit4.class)
 public final class WidgetsPredicationUpdateTaskTest {
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     private AppWidgetProviderInfo mApp1Provider1;
     private AppWidgetProviderInfo mApp1Provider2;
     private AppWidgetProviderInfo mApp2Provider1;
@@ -72,9 +85,12 @@
     private FakeBgDataModelCallback mCallback = new FakeBgDataModelCallback();
     private LauncherModelHelper mModelHelper;
     private UserHandle mUserHandle;
+    private LauncherApps mLauncherApps;
+
 
     @Before
     public void setup() throws Exception {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_CATEGORIZED_WIDGET_SUGGESTIONS);
         mModelHelper = new LauncherModelHelper();
 
         mUserHandle = myUserHandle();
@@ -93,6 +109,18 @@
         allWidgets = Arrays.asList(mApp1Provider1, mApp1Provider2, mApp2Provider1,
                 mApp4Provider1, mApp4Provider2, mApp5Provider1);
 
+        mLauncherApps = mModelHelper.sandboxContext.spyService(LauncherApps.class);
+        doAnswer(i -> {
+            String pkg = i.getArgument(0);
+            ApplicationInfo applicationInfo = ApplicationInfoBuilder.newBuilder()
+                    .setPackageName(pkg)
+                    .setName("App " + pkg)
+                    .build();
+            applicationInfo.category = CATEGORY_PRODUCTIVITY;
+            applicationInfo.flags = FLAG_INSTALLED;
+            return applicationInfo;
+        }).when(mLauncherApps).getApplicationInfo(anyString(), anyInt(), any());
+
         AppWidgetManager manager = mModelHelper.sandboxContext.spyService(AppWidgetManager.class);
         doReturn(allWidgets).when(manager).getInstalledProviders();
         doReturn(allWidgets).when(manager).getInstalledProvidersForProfile(eq(myUserHandle()));
@@ -140,12 +168,16 @@
             // 1. app5/provider1 & app4/provider1 have already been added to workspace. They are
             //    excluded from the result.
             // 2. app3 doesn't have a widget.
-            // 3. only 1 widget is picked from app1 because we only want to promote one widget per app.
+            // 3. only 1 widget is picked from app1 because we only want to promote one widget
+            // per app.
             List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
                     .stream()
                     .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
                     .collect(Collectors.toList());
             assertThat(recommendedWidgets).hasSize(2);
+            recommendedWidgets.forEach(pendingAddWidgetInfo ->
+                    assertThat(pendingAddWidgetInfo.recommendationCategory).isNotNull()
+            );
             assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1);
             assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
         });
@@ -179,6 +211,9 @@
                     .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
                     .collect(Collectors.toList());
             assertThat(recommendedWidgets).hasSize(2);
+            recommendedWidgets.forEach(pendingAddWidgetInfo ->
+                    assertThat(pendingAddWidgetInfo.recommendationCategory).isNotNull()
+            );
             // Another widget from the same package
             assertWidgetInfo(recommendedWidgets.get(0).info, mApp4Provider2);
             assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
@@ -192,7 +227,7 @@
     }
 
     private WidgetsPredictionUpdateTask newWidgetsPredicationTask(List<AppTarget> appTargets) {
-       return new WidgetsPredictionUpdateTask(
+        return new WidgetsPredictionUpdateTask(
                 new PredictorState(CONTAINER_WIDGETS_PREDICTION, "test_widgets_prediction"),
                 appTargets);
     }
diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredictionsRequesterTest.kt b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredictionsRequesterTest.kt
new file mode 100644
index 0000000..5c7b4ab
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredictionsRequesterTest.kt
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.app.prediction.AppTarget
+import android.app.prediction.AppTargetEvent
+import android.app.prediction.AppTargetId
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Context
+import android.os.Process.myUserHandle
+import android.os.UserHandle
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+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.WidgetPredictionsRequester.buildBundleForPredictionSession
+import com.android.launcher3.model.WidgetPredictionsRequester.filterPredictions
+import com.android.launcher3.model.WidgetPredictionsRequester.notOnUiSurfaceFilter
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Predicate
+import junit.framework.Assert.assertNotNull
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidJUnit4::class)
+class WidgetsPredictionsRequesterTest {
+
+    private lateinit var mUserHandle: UserHandle
+    private lateinit var context: Context
+    private lateinit var deviceProfile: DeviceProfile
+    private lateinit var testInvariantProfile: InvariantDeviceProfile
+
+    private lateinit var widget1aInfo: AppWidgetProviderInfo
+    private lateinit var widget1bInfo: AppWidgetProviderInfo
+    private lateinit var widget2Info: AppWidgetProviderInfo
+
+    private lateinit var widgetItem1a: WidgetItem
+    private lateinit var widgetItem1b: WidgetItem
+    private lateinit var widgetItem2: WidgetItem
+
+    private lateinit var allWidgets: Map<PackageUserKey, List<WidgetItem>>
+
+    @Mock private lateinit var iconCache: IconCache
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        mUserHandle = myUserHandle()
+        context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+        testInvariantProfile = LauncherAppState.getIDP(context)
+        deviceProfile = testInvariantProfile.getDeviceProfile(context).copy(context)
+
+        widget1aInfo =
+            createAppWidgetProviderInfo(
+                ComponentName.createRelative(APP_1_PACKAGE_NAME, APP_1_PROVIDER_A_CLASS_NAME)
+            )
+        widget1bInfo =
+            createAppWidgetProviderInfo(
+                ComponentName.createRelative(APP_1_PACKAGE_NAME, APP_1_PROVIDER_B_CLASS_NAME)
+            )
+        widgetItem1a = createWidgetItem(widget1aInfo)
+        widgetItem1b = createWidgetItem(widget1bInfo)
+
+        widget2Info =
+            createAppWidgetProviderInfo(
+                ComponentName.createRelative(APP_2_PACKAGE_NAME, APP_2_PROVIDER_1_CLASS_NAME)
+            )
+        widgetItem2 = createWidgetItem(widget2Info)
+
+        allWidgets =
+            mapOf(
+                PackageUserKey(APP_1_PACKAGE_NAME, mUserHandle) to
+                    listOf(widgetItem1a, widgetItem1b),
+                PackageUserKey(APP_2_PACKAGE_NAME, mUserHandle) to listOf(widgetItem2),
+            )
+    }
+
+    @Test
+    fun buildBundleForPredictionSession_includesAddedAppWidgets() {
+        val existingWidgets = arrayListOf(widget1aInfo, widget1bInfo, widget2Info)
+
+        val bundle = buildBundleForPredictionSession(existingWidgets, TEST_UI_SURFACE)
+        val addedWidgetsBundleExtra =
+            bundle.getParcelableArrayList(BUNDLE_KEY_ADDED_APP_WIDGETS, AppTarget::class.java)
+
+        assertNotNull(addedWidgetsBundleExtra)
+        assertThat(addedWidgetsBundleExtra)
+            .containsExactly(
+                buildExpectedAppTargetEvent(
+                    /*pkg=*/ APP_1_PACKAGE_NAME,
+                    /*providerClassName=*/ APP_1_PROVIDER_A_CLASS_NAME,
+                    /*user=*/ mUserHandle
+                ),
+                buildExpectedAppTargetEvent(
+                    /*pkg=*/ APP_1_PACKAGE_NAME,
+                    /*providerClassName=*/ APP_1_PROVIDER_B_CLASS_NAME,
+                    /*user=*/ mUserHandle
+                ),
+                buildExpectedAppTargetEvent(
+                    /*pkg=*/ APP_2_PACKAGE_NAME,
+                    /*providerClassName=*/ APP_2_PROVIDER_1_CLASS_NAME,
+                    /*user=*/ mUserHandle
+                )
+            )
+    }
+
+    @Test
+    fun filterPredictions_notOnUiSurfaceFilter_returnsOnlyEligiblePredictions() {
+        val widgetsAlreadyOnSurface = arrayListOf(widget1bInfo)
+        val filter: Predicate<WidgetItem> = notOnUiSurfaceFilter(widgetsAlreadyOnSurface)
+
+        val predictions =
+            listOf(
+                // already on surface
+                AppTarget(
+                    AppTargetId(APP_1_PACKAGE_NAME),
+                    APP_1_PACKAGE_NAME,
+                    APP_1_PROVIDER_B_CLASS_NAME,
+                    mUserHandle
+                ),
+                // eligible
+                AppTarget(
+                    AppTargetId(APP_2_PACKAGE_NAME),
+                    APP_2_PACKAGE_NAME,
+                    APP_2_PROVIDER_1_CLASS_NAME,
+                    mUserHandle
+                )
+            )
+
+        // only 2 was eligible
+        assertThat(filterPredictions(predictions, allWidgets, filter)).containsExactly(widgetItem2)
+    }
+
+    @Test
+    fun filterPredictions_appPredictions_returnsWidgetFromPackage() {
+        val widgetsAlreadyOnSurface = arrayListOf(widget1bInfo)
+        val filter: Predicate<WidgetItem> = notOnUiSurfaceFilter(widgetsAlreadyOnSurface)
+
+        val predictions =
+            listOf(
+                AppTarget(
+                    AppTargetId(APP_1_PACKAGE_NAME),
+                    APP_1_PACKAGE_NAME,
+                    "$APP_1_PACKAGE_NAME.SomeActivity",
+                    mUserHandle
+                ),
+                AppTarget(
+                    AppTargetId(APP_2_PACKAGE_NAME),
+                    APP_2_PACKAGE_NAME,
+                    "$APP_2_PACKAGE_NAME.SomeActivity2",
+                    mUserHandle
+                ),
+            )
+
+        assertThat(filterPredictions(predictions, allWidgets, filter))
+            .containsExactly(widgetItem1a, widgetItem2)
+    }
+
+    private fun createWidgetItem(
+        providerInfo: AppWidgetProviderInfo,
+    ): WidgetItem {
+        val widgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo)
+        return WidgetItem(widgetInfo, testInvariantProfile, iconCache, context)
+    }
+
+    companion object {
+        const val TEST_UI_SURFACE = "widgets_test"
+        const val BUNDLE_KEY_ADDED_APP_WIDGETS = "added_app_widgets"
+
+        const val APP_1_PACKAGE_NAME = "com.example.app1"
+        const val APP_1_PROVIDER_A_CLASS_NAME = "app1Provider1"
+        const val APP_1_PROVIDER_B_CLASS_NAME = "app1Provider2"
+
+        const val APP_2_PACKAGE_NAME = "com.example.app2"
+        const val APP_2_PROVIDER_1_CLASS_NAME = "app2Provider1"
+
+        const val TEST_PACKAGE = "pkg"
+
+        private fun buildExpectedAppTargetEvent(
+            pkg: String,
+            providerClassName: String,
+            userHandle: UserHandle
+        ): AppTargetEvent {
+            val appTarget =
+                AppTarget.Builder(
+                        /*id=*/ AppTargetId("widget:$pkg"),
+                        /*packageName=*/ pkg,
+                        /*user=*/ userHandle
+                    )
+                    .setClassName(providerClassName)
+                    .build()
+            return AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_PIN)
+                .setLaunchLocation(TEST_UI_SURFACE)
+                .build()
+        }
+    }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
new file mode 100644
index 0000000..93eefe2
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import android.util.SparseArray
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidTestingRunner::class)
+class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+
+    @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+    @Mock private lateinit var mockRecentsModel: RecentsModel
+    @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
+
+    private var nextTaskId: Int = 500
+
+    private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
+    private lateinit var userHandle: UserHandle
+
+    @Before
+    fun setUp() {
+        super.setup()
+        userHandle = Process.myUserHandle()
+        taskbarRunningAppsController =
+            DesktopTaskbarRunningAppsController(mockRecentsModel, mockDesktopVisibilityController)
+        taskbarRunningAppsController.init(taskbarControllers)
+        taskbarRunningAppsController.setApps(
+            ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
+        )
+    }
+
+    @Test
+    fun updateHotseatItemInfos_null_returnsNull() {
+        assertThat(taskbarRunningAppsController.updateHotseatItemInfos(/* hotseatItems= */ null))
+            .isNull()
+    }
+
+    @Test
+    fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
+        setInDesktopMode(false)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+                .toTypedArray()
+
+        assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+            .isEqualTo(hotseatItems)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() {
+        setInDesktopMode(false)
+        val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
+        val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(hotseatPackages)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
+        setInDesktopMode(true)
+        val hotseatItems: Array<ItemInfo> =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+                .toTypedArray()
+
+        assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+            .isEqualTo(hotseatItems)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() {
+        setInDesktopMode(true)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+        val runningTasks =
+            createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        val expectedPackages =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+            )
+        assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(expectedPackages)
+    }
+
+    @Test
+    fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() {
+        setInDesktopMode(true)
+        val hotseatItems =
+            createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+        val runningTasks =
+            createDesktopTasksFromPackageNames(
+                listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+            )
+        whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+        taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+        val newHotseatItems =
+            taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+        val expectedPackages =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+            )
+        assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(expectedPackages)
+    }
+
+    private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
+        return packageNames.map { createTestAppInfo(packageName = it) }
+    }
+
+    private fun createDesktopTasksFromPackageNames(
+        packageNames: List<String>
+    ): ArrayList<RunningTaskInfo> {
+        return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
+    }
+
+    private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+        return RunningTaskInfo().apply {
+            taskId = nextTaskId++
+            configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+            realActivity = ComponentName(packageName, "TestActivity")
+        }
+    }
+
+    private fun createTestAppInfo(
+        packageName: String = "testPackageName",
+        className: String = "testClassName"
+    ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
+
+    private fun setInDesktopMode(inDesktopMode: Boolean) {
+        whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
+    }
+
+    private fun createSparseArray(itemInfos: List<ItemInfo>): SparseArray<ItemInfo> {
+        val sparseArray = SparseArray<ItemInfo>()
+        itemInfos.forEachIndexed { index, itemInfo -> sparseArray[index] = itemInfo }
+        return sparseArray
+    }
+
+    private companion object {
+        const val HOTSEAT_PACKAGE_1 = "hotseat1"
+        const val HOTSEAT_PACKAGE_2 = "hotseat2"
+        const val RUNNING_APP_PACKAGE_1 = "running1"
+        const val RUNNING_APP_PACKAGE_2 = "running2"
+        const val RUNNING_APP_PACKAGE_3 = "running3"
+        val ALL_APP_PACKAGES =
+            listOf(
+                HOTSEAT_PACKAGE_1,
+                HOTSEAT_PACKAGE_2,
+                RUNNING_APP_PACKAGE_1,
+                RUNNING_APP_PACKAGE_2,
+                RUNNING_APP_PACKAGE_3,
+            )
+    }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
new file mode 100644
index 0000000..3f947a0
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -0,0 +1,5 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
+
diff --git a/quickstep/tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java b/quickstep/tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java
new file mode 100644
index 0000000..68ac3d5
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.testcomponent;
+
+/**
+ * Extension of BaseTestingActivity to help test excludeFromRecents="true".
+ */
+public class ExcludeFromRecentsTestActivity extends BaseTestingActivity {}
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index 3a5fb04..44c23ba 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -16,8 +16,6 @@
 
 package com.android.quickstep;
 
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
-
 import static org.junit.Assert.assertTrue;
 
 import android.os.SystemProperties;
@@ -25,11 +23,9 @@
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.Until;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.tapl.LaunchedAppState;
-import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.views.RecentsView;
 
 import org.junit.rules.RuleChain;
@@ -38,7 +34,7 @@
 /**
  * Base class for all instrumentation tests that deal with Quickstep.
  */
-public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
+public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest<QuickstepLauncher> {
     public static final boolean ENABLE_SHELL_TRANSITIONS =
             SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
     @Override
@@ -50,38 +46,13 @@
     }
 
     @Override
-    protected void onLauncherActivityClose(Launcher launcher) {
+    protected void onLauncherActivityClose(QuickstepLauncher launcher) {
         RecentsView recentsView = launcher.getOverviewPanel();
         if (recentsView != null) {
             recentsView.finishRecentsAnimation(false /* toRecents */, null);
         }
     }
 
-    @Override
-    protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
-            boolean isResumed, boolean isStarted) {
-        if (ENABLE_SHELL_TRANSITIONS || !isInLiveTileMode(launcher, expectedContainerType)) {
-            super.checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
-        } else {
-            assertTrue("[Live Tile] hasBeenResumed() == isStarted(), hasBeenResumed(): "
-                            + isResumed, isResumed != isStarted);
-        }
-    }
-
-    @Override
-    protected void checkLauncherStateInOverview(Launcher launcher,
-            ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
-        if (ENABLE_SHELL_TRANSITIONS || !isInLiveTileMode(launcher, expectedContainerType)) {
-            super.checkLauncherStateInOverview(launcher, expectedContainerType, isStarted,
-                    isResumed);
-        } else {
-            assertTrue(
-                    "[Live Tile] Launcher is not started or has been resumed in state: "
-                            + expectedContainerType,
-                    isStarted && !isResumed);
-        }
-    }
-
     protected void assertTestActivityIsRunning(int activityNumber, String message) {
         assertTrue(message, mDevice.wait(
                 Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity" + activityNumber)),
@@ -96,15 +67,4 @@
                 isInLaunchedApp(launcher)));
         return launchedAppState;
     }
-
-    private boolean isInLiveTileMode(Launcher launcher,
-            LauncherInstrumentation.ContainerType expectedContainerType) {
-        if (expectedContainerType != LauncherInstrumentation.ContainerType.OVERVIEW) {
-            return false;
-        }
-
-        RecentsView recentsView = launcher.getOverviewPanel();
-        return recentsView.getSizeStrategy().isInLiveTileMode()
-                && recentsView.getRunningTaskViewId() != -1;
-    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
index fc757b4..ca5fb70 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
@@ -55,7 +55,7 @@
                 "com.android.launcher3.testcomponent.BaseTestingActivity");
         mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, layoutBuilder);
         AbstractLauncherUiTest.initialize(this);
-        startAppFast(CALCULATOR_APP_PACKAGE);
+        startAppFastInFullscreen(CALCULATOR_APP_PACKAGE);
         mLauncher.enableBlockTimeout(true);
         mLauncher.showTaskbarIfHidden();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
new file mode 100644
index 0000000..0f9d96c
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import android.content.ComponentName
+import android.content.Intent
+import android.platform.test.flag.junit.SetFlagsRule
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.AbstractFloatingViewHelper
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.quickstep.views.LauncherRecentsView
+import com.android.quickstep.views.TaskView
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.android.window.flags.Flags
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.quality.Strictness
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** Test for DesktopSystemShortcut */
+class DesktopSystemShortcutTest {
+
+    @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+    private val launcher: QuickstepLauncher = mock()
+    private val statsLogManager: StatsLogManager = mock()
+    private val statsLogger: StatsLogManager.StatsLogger = mock()
+    private val recentsView: LauncherRecentsView = mock()
+    private val taskView: TaskView = mock()
+    private val workspaceItemInfo: WorkspaceItemInfo = mock()
+    private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock()
+    private val factory: TaskShortcutFactory =
+        DesktopSystemShortcut.createFactory(abstractFloatingViewHelper)
+
+    private lateinit var mockitoSession: StaticMockitoSession
+
+    @Before
+    fun setUp(){
+        mockitoSession = mockitoSession().strictness(Strictness.LENIENT)
+                .spyStatic(DesktopModeStatus::class.java).startMocking()
+        doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+    }
+
+    @After
+    fun tearDown(){
+        mockitoSession.finishMocking()
+    }
+
+    @Test
+    fun createDesktopTaskShortcutFactory_desktopModeDisabled() {
+        setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskIdAttributeContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNull()
+    }
+
+    @Test
+    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskIdAttributeContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNull()
+    }
+
+    @Test
+    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+        doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+        doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskIdAttributeContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNotNull()
+    }
+
+    @Test
+    fun createDesktopTaskShortcutFactory_undockable() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = false
+            }
+        val taskContainer =
+            taskView.TaskIdAttributeContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+            )
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).isNull()
+    }
+
+    @Test
+    fun desktopSystemShortcutClicked() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+
+        val task =
+            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+                isDockable = true
+            }
+        val taskContainer =
+            taskView.TaskIdAttributeContainer(
+                task,
+                null,
+                null,
+                SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+            )
+
+        whenever(launcher.getOverviewPanel<LauncherRecentsView>()).thenReturn(recentsView)
+        whenever(launcher.statsLogManager).thenReturn(statsLogManager)
+        whenever(statsLogManager.logger()).thenReturn(statsLogger)
+        whenever(statsLogger.withItemInfo(any())).thenReturn(statsLogger)
+        whenever(taskView.getItemInfo(task)).thenReturn(workspaceItemInfo)
+        whenever(recentsView.moveTaskToDesktop(any(), any())).thenAnswer {
+            val successCallback = it.getArgument<Runnable>(1)
+            successCallback.run()
+        }
+
+        val shortcuts = factory.getShortcuts(launcher, taskContainer)
+        assertThat(shortcuts).hasSize(1)
+        assertThat(shortcuts!!.first()).isInstanceOf(DesktopSystemShortcut::class.java)
+
+        val desktopShortcut = shortcuts.first() as DesktopSystemShortcut
+
+        desktopShortcut.onClick(taskView)
+
+        val allTypesExceptRebindSafe =
+            AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+        verify(abstractFloatingViewHelper).closeOpenViews(launcher, true, allTypesExceptRebindSafe)
+        verify(recentsView).moveTaskToDesktop(eq(taskContainer), any())
+        verify(statsLogger).withItemInfo(workspaceItemInfo)
+        verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP)
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 8d54dce..2858929 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -28,7 +28,7 @@
 import static com.android.launcher3.ui.AbstractLauncherUiTest.resolveSystemApp;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.startAppFast;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.startTestActivity;
-import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
+import static com.android.launcher3.ui.TaplTestsLauncher3Test.getAppPackageName;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.rule.ShellCommandRule.disableHeadsUpNotification;
 import static com.android.launcher3.util.rule.ShellCommandRule.getLauncherCommand;
@@ -57,6 +57,7 @@
 import com.android.launcher3.testcomponent.TestCommandReceiver;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
 import com.android.launcher3.util.rule.FailureWatcher;
 import com.android.launcher3.util.rule.SamplerRule;
 import com.android.launcher3.util.rule.ScreenRecordRule;
@@ -67,7 +68,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -75,16 +75,21 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.model.Statement;
 
+import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class FallbackRecentsTest {
 
     private static final String FALLBACK_LAUNCHER_TITLE = "Test launcher";
+    private static final Pattern COMPONENT_INFO_REGEX = Pattern.compile("ComponentInfo\\{(.*)\\}");
 
     private final UiDevice mDevice;
     private final LauncherInstrumentation mLauncher;
@@ -99,6 +104,9 @@
     @Rule
     public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
 
+    @Rule
+    public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
+
     public FallbackRecentsTest() throws RemoteException {
         Instrumentation instrumentation = getInstrumentation();
         Context context = instrumentation.getContext();
@@ -106,8 +114,6 @@
         mDevice.setOrientationNatural();
         mLauncher = AbstractLauncherUiTest.createLauncherInstrumentation();
         mLauncher.enableDebugTracing();
-        // b/143488140
-        //mLauncher.enableCheckEventsForSuccessfulGestures();
 
         if (TestHelpers.isInLauncherProcess()) {
             Utilities.enableRunningInTestHarnessForTests();
@@ -130,9 +136,7 @@
                     TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
                     UiDevice.getInstance(getInstrumentation()).executeShellCommand(
                             getLauncherCommand(getLauncherInMyProcess()));
-                    // b/143488140
-                    mDevice.pressHome();
-                    mDevice.waitForIdle();
+                    pressHomeAndWaitForOverviewClose();
                 }
             }
         };
@@ -175,8 +179,6 @@
         }
     }
 
-    // b/143488140
-    //@NavigationModeSwitch
     @Test
     public void goToOverviewFromHome() {
         mDevice.pressHome();
@@ -186,12 +188,11 @@
         mLauncher.getLaunchedAppState().switchToOverview();
     }
 
-    // b/143488140
     //@NavigationModeSwitch
-    @Ignore
     @Test
     public void goToOverviewFromApp() {
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
+        waitForRecentsActivityStop();
 
         mLauncher.getLaunchedAppState().switchToOverview();
     }
@@ -218,21 +219,47 @@
     }
 
     private BaseOverview pressHomeAndGoToOverview() {
-        mDevice.pressHome();
+        pressHomeAndWaitForOverviewClose();
         return mLauncher.getLaunchedAppState().switchToOverview();
     }
 
-    // b/143488140
-    //@NavigationModeSwitch
+    private void pressHomeAndWaitForOverviewClose() {
+        mDevice.pressHome();
+        waitForRecentsActivityStop();
+    }
+
+    private void waitForRecentsActivityStop() {
+        try {
+            final boolean recentsActivityIsNull = MAIN_EXECUTOR.submit(
+                    () -> RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity() == null).get();
+            if (recentsActivityIsNull) {
+                // Null activity counts as a "stopped" one.
+                return;
+            }
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        Wait.atMost("Recents activity didn't stop",
+                () -> getFromRecents(recents -> !recents.isStarted()),
+                DEFAULT_UI_TIMEOUT, mLauncher);
+    }
+
     @Test
-    public void testOverview() {
+    public void testOverview() throws IOException {
         startAppFast(getAppPackageName());
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
         startTestActivity(2);
+        waitForRecentsActivityStop();
         Wait.atMost("Expected three apps in the task list",
                 () -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
 
+        checkTestLauncher();
         BaseOverview overview = mLauncher.getLaunchedAppState().switchToOverview();
+        checkTestLauncher();
+
         executeOnRecents(recents -> {
             assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3);
         });
@@ -274,6 +301,17 @@
                 mOtherLauncherActivity.packageName).text(FALLBACK_LAUNCHER_TITLE)), WAIT_TIME_MS));
     }
 
+    private void checkTestLauncher() throws IOException {
+        final Matcher matcher = COMPONENT_INFO_REGEX.matcher(
+                mDevice.executeShellCommand("cmd shortcut get-default-launcher"));
+        assertTrue("Incorrect output from get-default-launcher", matcher.find());
+        assertEquals("Current Launcher activity is incorrect",
+                "com.google.android.apps.nexuslauncher.tests/com.android"
+                        + ".launcher3.testcomponent.TestLauncherActivity",
+                matcher.group(1)
+        );
+    }
+
     private int getCurrentOverviewPage(RecentsActivity recents) {
         return recents.<RecentsView>getOverviewPanel().getCurrentPage();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
index a347156..a388510 100644
--- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
@@ -42,12 +42,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(70)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1445)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(580)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1445)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1435)
     }
 
     /**
@@ -64,12 +66,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(4)
         assertThat(dp.hotseatBorderSpace).isEqualTo(40)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1080)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(550)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1080)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1070)
     }
 
     /**
@@ -85,12 +89,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(54)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1468)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(231)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(759)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1468)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1455)
     }
 
     /**
@@ -100,22 +106,21 @@
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
-        inv?.apply {
-            hotseatColumnSpan = IntArray(4) { 4 }
-            inlineQsb = BooleanArray(4) { false }
-        }
+        inv?.apply { inlineQsb = BooleanArray(4) { false } }
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(100)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1975)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(1040)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1233)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1965)
     }
 
     /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@@ -128,13 +133,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(36)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(34)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(4)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1179)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(864)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(696)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(876)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(694)
 
         assertThat(dp.isQsbInline).isTrue()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(528)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(542)
     }
 
     /**
@@ -151,6 +158,8 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(5)
         assertThat(dp.hotseatBorderSpace).isEqualTo(36)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(4)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1095)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(816)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(700)
@@ -158,4 +167,23 @@
         assertThat(dp.isQsbInline).isTrue()
         assertThat(dp.hotseatQsbWidth).isEqualTo(480)
     }
+
+    @Test
+    fun increase_span_when_space_between_icons_is_less_than_minimum() {
+        initializeVarsForTwoPanel(isGestureMode = false, isLandscape = false, rows = 5, cols = 5)
+        val dp = newDP()
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(600)
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(48)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(8)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1383)
+
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(126)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(652)
+
+        assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1372)
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index 53bc2a2..2916952 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -2,17 +2,15 @@
 
 import android.content.Context
 import android.testing.AndroidTestingRunner
-import android.view.Display
-import android.view.IWindowManager
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.filters.SmallTest
 import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
 import com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE
 import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
 import com.android.launcher3.util.DisplayController.Info
-import com.android.launcher3.util.Executors
 import com.android.launcher3.util.NavigationMode
 import com.android.launcher3.util.window.WindowManagerProxy
+import com.android.quickstep.util.GestureExclusionManager
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -28,7 +26,7 @@
 @RunWith(AndroidTestingRunner::class)
 class RecentsAnimationDeviceStateTest {
 
-    @Mock private lateinit var windowManager: IWindowManager
+    @Mock private lateinit var exclusionManager: GestureExclusionManager
     @Mock private lateinit var windowManagerProxy: WindowManagerProxy
     @Mock private lateinit var info: Info
 
@@ -38,60 +36,45 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        underTest = RecentsAnimationDeviceState(context, windowManager)
+        underTest = RecentsAnimationDeviceState(context, exclusionManager)
     }
 
     @Test
     fun registerExclusionListener_success() {
         underTest.registerExclusionListener()
 
-        awaitTasksCompleted()
-        verify(windowManager)
-            .registerSystemGestureExclusionListener(
-                underTest.mGestureExclusionListener,
-                Display.DEFAULT_DISPLAY
-            )
+        verify(exclusionManager).addListener(underTest)
     }
 
     @Test
     fun registerExclusionListener_again_fail() {
         underTest.registerExclusionListener()
-        awaitTasksCompleted()
-        reset(windowManager)
+        reset(exclusionManager)
 
         underTest.registerExclusionListener()
 
-        awaitTasksCompleted()
-        verifyZeroInteractions(windowManager)
+        verifyZeroInteractions(exclusionManager)
     }
 
     @Test
     fun unregisterExclusionListener_success() {
         underTest.registerExclusionListener()
-        awaitTasksCompleted()
-        reset(windowManager)
+        reset(exclusionManager)
 
         underTest.unregisterExclusionListener()
 
-        awaitTasksCompleted()
-        verify(windowManager)
-            .unregisterSystemGestureExclusionListener(
-                underTest.mGestureExclusionListener,
-                Display.DEFAULT_DISPLAY
-            )
+        verify(exclusionManager).removeListener(underTest)
     }
 
     @Test
     fun unregisterExclusionListener_again_fail() {
         underTest.registerExclusionListener()
         underTest.unregisterExclusionListener()
-        awaitTasksCompleted()
-        reset(windowManager)
+        reset(exclusionManager)
 
         underTest.unregisterExclusionListener()
 
-        awaitTasksCompleted()
-        verifyZeroInteractions(windowManager)
+        verifyZeroInteractions(exclusionManager)
     }
 
     @Test
@@ -100,45 +83,28 @@
 
         underTest.onDisplayInfoChanged(context, info, CHANGE_ROTATION or CHANGE_NAVIGATION_MODE)
 
-        awaitTasksCompleted()
-        verify(windowManager)
-            .registerSystemGestureExclusionListener(
-                underTest.mGestureExclusionListener,
-                Display.DEFAULT_DISPLAY
-            )
+        verify(exclusionManager).addListener(underTest)
     }
 
     @Test
     fun onDisplayInfoChanged_twoButton_unregisterExclusionListener() {
         underTest.registerExclusionListener()
-        awaitTasksCompleted()
         whenever(info.getNavigationMode()).thenReturn(NavigationMode.TWO_BUTTONS)
-        reset(windowManager)
+        reset(exclusionManager)
 
         underTest.onDisplayInfoChanged(context, info, CHANGE_ROTATION or CHANGE_NAVIGATION_MODE)
 
-        awaitTasksCompleted()
-        verify(windowManager)
-            .unregisterSystemGestureExclusionListener(
-                underTest.mGestureExclusionListener,
-                Display.DEFAULT_DISPLAY
-            )
+        verify(exclusionManager).removeListener(underTest)
     }
 
     @Test
     fun onDisplayInfoChanged_changeDensity_noOp() {
         underTest.registerExclusionListener()
-        awaitTasksCompleted()
         whenever(info.getNavigationMode()).thenReturn(NavigationMode.NO_BUTTON)
-        reset(windowManager)
+        reset(exclusionManager)
 
         underTest.onDisplayInfoChanged(context, info, CHANGE_DENSITY)
 
-        awaitTasksCompleted()
-        verifyZeroInteractions(windowManager)
-    }
-
-    private fun awaitTasksCompleted() {
-        Executors.UI_HELPER_EXECUTOR.submit<Any> { null }.get()
+        verifyZeroInteractions(exclusionManager)
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 728fe67..4aa7cb0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -17,8 +17,6 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -84,8 +82,7 @@
     }
 
     private DigitalWellBeingToast getToast() {
-        executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW));
-        waitForState("Launcher internal state didn't switch to Overview", () -> OVERVIEW);
+        mLauncher.getWorkspace().switchToOverview();
         final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
 
         return getFromLauncher(launcher -> {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index 3f806d1..fa10b61 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep;
 
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
@@ -25,28 +24,23 @@
 import android.content.Intent;
 import android.platform.test.annotations.PlatinumTest;
 
+import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask;
 import com.android.launcher3.tapl.OverviewTaskMenu;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.rule.TestStabilityRule;
 
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * This test run in both Out of process (Oop) and in-process (Ipc).
  * Tests the app Icon in overview.
  */
-public class TaplOverviewIconTest extends AbstractLauncherUiTest {
+public class TaplOverviewIconTest extends AbstractLauncherUiTest<QuickstepLauncher> {
 
     private static final String CALCULATOR_APP_PACKAGE =
             resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
 
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
-
     @PlatinumTest(focusArea = "launcher")
     @Test
     public void testOverviewActionsMenu() {
@@ -86,7 +80,8 @@
         taskMenu.touchOutsideTaskMenuToDismiss();
 
         OverviewTaskMenu splitMenu =
-                mLauncher.goHome().switchToOverview().getCurrentTask().tapSplitTaskMenu();
+                mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu(
+                        OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT);
         assertTrue("App info item not appearing in expanded split task's menu.",
                 splitMenu.hasMenuItem("App info"));
         splitMenu.touchOutsideTaskMenuToDismiss();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
new file mode 100644
index 0000000..857a4e3
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import android.util.Log;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+
+import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.rule.ScreenRecordRule;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.util.Objects;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplPrivateSpaceTest extends AbstractQuickStepTest {
+
+    private int mProfileUserId;
+    private boolean mPrivateProfileSetupSuccessful;
+    private static final String TAG = "TaplPrivateSpaceTest";
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        initialize(this);
+
+        createAndStartPrivateProfileUser();
+        assumeTrue("Private Profile Setup not successful, aborting",
+                mPrivateProfileSetupSuccessful);
+
+        mDevice.pressHome();
+        waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal",
+                () -> NORMAL);
+        waitForResumed("Launcher internal state is still Background");
+        mLauncher.getWorkspace().switchToAllApps();
+        waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps",
+                () -> ALL_APPS);
+
+        // Wait for Private Space being available in Launcher.
+        waitForPrivateSpaceSetup();
+        // Wait for Launcher UI to be updated with Private Space Items.
+        waitForLauncherUIUpdate();
+    }
+
+    private void createAndStartPrivateProfileUser() {
+        String createUserOutput = executeShellCommand("pm create-user --profileOf 0 --user-type "
+                + "android.os.usertype.profile.PRIVATE LauncherPrivateProfile");
+        updatePrivateProfileSetupSuccessful("pm create-user", createUserOutput);
+        String[] tokens = createUserOutput.split("\\s+");
+        mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
+        StringBuilder logStr = new StringBuilder().append("profileId: ").append(mProfileUserId);
+        for (String str : tokens) {
+            logStr.append(str).append("\n");
+        }
+        String startUserOutput = executeShellCommand("am start-user " + mProfileUserId);
+        updatePrivateProfileSetupSuccessful("am start-user", startUserOutput);
+    }
+
+    @After
+    public void removePrivateProfile() {
+        String output = executeShellCommand("pm remove-user " + mProfileUserId);
+        updateProfileRemovalSuccessful("pm remove-user", output);
+        waitForPrivateSpaceRemoval();
+    }
+
+    @Test
+    @ScreenRecordRule.ScreenRecord // b/334946529
+    public void testPrivateSpaceContainerIsPresent() {
+        assumeTrue(mPrivateProfileSetupSuccessful);
+        // Scroll to the bottom of All Apps
+        executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
+        waitForResumed("Launcher internal state is still Background");
+
+        // Verify Unlocked View elements are present.
+        assertNotNull("Private Space Unlocked View not found, or is not correct",
+                mLauncher.getAllApps().getPrivateSpaceUnlockedView());
+    }
+
+    private void waitForPrivateSpaceSetup() {
+        waitForLauncherCondition("Private Profile not setup",
+                launcher -> launcher.getAppsView().hasPrivateProfile(),
+                LauncherInstrumentation.WAIT_TIME_MS);
+    }
+
+    private void waitForPrivateSpaceRemoval() {
+        waitForLauncherCondition("Private Profile not setup",
+                launcher -> !launcher.getAppsView().hasPrivateProfile(),
+                LauncherInstrumentation.WAIT_TIME_MS);
+    }
+
+    private void waitForLauncherUIUpdate() {
+        // Wait for model thread completion as it may be processing
+        // the install event from the SystemService
+        mLauncher.waitForModelQueueCleared();
+        // Wait for Launcher UI thread completion, as it may be processing updating the UI in
+        // response to the model update. Not that `waitForLauncherInitialized` is just a proxy
+        // method, we can use any method which touches Launcher UI thread,
+        mLauncher.waitForLauncherInitialized();
+    }
+
+    private void updatePrivateProfileSetupSuccessful(String cli, String output) {
+        Log.d(TAG, "updatePrivateProfileSetupSuccessful, cli=" + cli + " " + "output="
+                + output);
+        mPrivateProfileSetupSuccessful = output.startsWith("Success");
+    }
+
+    private void updateProfileRemovalSuccessful(String cli, String output) {
+        Log.d(TAG, "updateProfileRemovalSuccessful, cli=" + cli + " " + "output=" + output);
+        assertTrue(output, output.startsWith("Success"));
+    }
+
+    private String executeShellCommand(String command) {
+        try {
+            return mDevice.executeShellCommand(command);
+        } catch (IOException e) {
+            Log.e(TAG, "error running shell command", e);
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index 7e274e8..1886ce6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -16,14 +16,9 @@
 
 package com.android.quickstep;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.Before;
@@ -40,8 +35,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        AbstractLauncherUiTest.initialize(this);
-        // b/143488140
         mLauncher.goHome();
         // Start an activity where the gestures start.
         startTestActivity(2);
@@ -49,8 +42,6 @@
 
     @Test
     @NavigationModeSwitch
-    // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     public void testStressPressHome() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
@@ -63,8 +54,6 @@
 
     @Test
     @NavigationModeSwitch
-    // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     public void testStressSwipeToOverview() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
index 829e54b..7ab72f2 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
@@ -22,7 +22,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.tapl.KeyboardQuickSwitch;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.taskbar.KeyboardQuickSwitchController;
 
 import org.junit.Assume;
 import org.junit.Test;
@@ -33,14 +33,23 @@
 public class TaplTestsKeyboardQuickSwitch extends AbstractQuickStepTest {
 
     private enum TestSurface {
-        HOME, LAUNCHED_APP, HOME_ALL_APPS, WIDGETS,
+        HOME(true),
+        LAUNCHED_APP(false),
+        HOME_ALL_APPS(true),
+        WIDGETS(true);
+
+        private final boolean mInitialFocusAtZero;
+
+        TestSurface(boolean initialFocusAtZero) {
+            mInitialFocusAtZero = initialFocusAtZero;
+        }
     }
 
     private enum TestCase {
         DISMISS(0),
         LAUNCH_LAST_APP(0),
         LAUNCH_SELECTED_APP(1),
-        LAUNCH_OVERVIEW(5);
+        LAUNCH_OVERVIEW(KeyboardQuickSwitchController.MAX_TASKS - 1);
 
         private final int mNumAdditionalRunningTasks;
 
@@ -56,8 +65,7 @@
     public void setUp() throws Exception {
         Assume.assumeTrue(mLauncher.isTablet());
         super.setUp();
-        AbstractLauncherUiTest.initialize(this);
-        startAppFast(CALCULATOR_APP_PACKAGE);
+        startAppFastInFullscreen(CALCULATOR_APP_PACKAGE);
         startTestActivity(2);
     }
 
@@ -141,6 +149,13 @@
         runTest(TestSurface.WIDGETS, TestCase.LAUNCH_OVERVIEW);
     }
 
+    @Test
+    public void testLaunchSingleRecentTask() {
+        mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
+        startAppFast(CALCULATOR_APP_PACKAGE);
+        mLauncher.goHome().showQuickSwitchView().launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
+    }
+
     private void runTest(@NonNull TestSurface testSurface, @NonNull TestCase testCase) {
         for (int i = 0; i < testCase.mNumAdditionalRunningTasks; i++) {
             startTestActivity(3 + i);
@@ -172,13 +187,24 @@
                 kqs.dismiss();
                 break;
             case LAUNCH_LAST_APP:
-                kqs.launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
+                kqs.launchFocusedAppTask(testSurface.mInitialFocusAtZero
+                        ? getAppPackageName() : CALCULATOR_APP_PACKAGE);
                 break;
             case LAUNCH_SELECTED_APP:
-                kqs.moveFocusForward().launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
+                kqs.moveFocusForward();
+                if (testSurface.mInitialFocusAtZero) {
+                    kqs.moveFocusForward();
+                }
+                kqs.launchFocusedAppTask(CALCULATOR_APP_PACKAGE);
                 break;
             case LAUNCH_OVERVIEW:
-                kqs.moveFocusBackward().moveFocusBackward().launchFocusedOverviewTask();
+                kqs.moveFocusBackward();
+                if (!testSurface.mInitialFocusAtZero) {
+                    kqs.moveFocusBackward();
+                }
+                kqs.launchFocusedOverviewTask()
+                        // Check that the correct task was focused
+                        .launchFocusedTaskByEnterKey(CALCULATOR_APP_PACKAGE);
                 break;
             default:
                 throw new IllegalStateException("Cannot run test case: " + testCase);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index c9e536a..a9ff161 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -15,15 +15,21 @@
  */
 package com.android.quickstep;
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
 
+import android.graphics.Rect;
+
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
+import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -39,4 +45,23 @@
         // Width check is performed inside TAPL whenever getTaskbar() is called.
         getTaskbar();
     }
+
+    @Test
+    @NavigationModeSwitch(mode = NavigationModeSwitchRule.Mode.THREE_BUTTON)
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+    public void testThreeButtonsTaskbarBoundsAfterConfigChangeDuringIme() {
+        Rect taskbarBoundsBefore = getTaskbar().getVisibleBounds();
+        // Go home and to an IME activity (any configuration change would do, as long as it
+        // triggers taskbar insets or height change while taskbar is stashed).
+        mLauncher.goHome();
+        startImeTestActivity();
+        // IME should stash the taskbar, which hides icons even in 3 button mode.
+        mLauncher.getLaunchedAppState().assertTaskbarHidden();
+        // Close IME to check new taskbar bounds.
+        startTestActivity(2);
+        Rect taskbarBoundsAfter = getTaskbar().getVisibleBounds();
+        Assert.assertEquals(
+                "Taskbar bounds are not the same after a configuration change while stashed.",
+                taskbarBoundsBefore, taskbarBoundsAfter);
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 6cbe171..81a2d54 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -21,6 +21,7 @@
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
@@ -28,7 +29,6 @@
 
 import android.content.Intent;
 import android.content.res.Configuration;
-import android.platform.test.annotations.PlatinumTest;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -38,13 +38,14 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.tapl.BaseOverview;
 import com.android.launcher3.tapl.LaunchedAppState;
 import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
 import com.android.launcher3.tapl.Overview;
 import com.android.launcher3.tapl.OverviewActions;
 import com.android.launcher3.tapl.OverviewTask;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.tapl.SelectModeButtons;
+import com.android.launcher3.tapl.Workspace;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
@@ -71,7 +72,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        AbstractLauncherUiTest.initialize(this);
         executeOnLauncher(launcher -> {
             RecentsView recentsView = launcher.getOverviewPanel();
             recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true);
@@ -112,7 +112,6 @@
 
     @Test
     @PortraitLandscape
-    @PlatinumTest(focusArea = "launcher")
     public void testOverview() throws Exception {
         startTestAppsWithCheck();
         // mLauncher.pressHome() also tests an important case of pressing home while in background.
@@ -194,6 +193,69 @@
         actionsView.clickAndDismissScreenshot();
     }
 
+    @Test
+    public void testDismissOverviewWithEscKey() throws Exception {
+        startTestAppsWithCheck();
+        final Overview overview = mLauncher.goHome().switchToOverview();
+        assertTrue("Launcher internal state is not Overview",
+                isInState(() -> LauncherState.OVERVIEW));
+
+        overview.dismissByEscKey();
+        assertTrue("Launcher internal state is not Home",
+                isInState(() -> LauncherState.NORMAL));
+    }
+
+    @Test
+    public void testDismissModalTaskAndOverviewWithEscKey() throws Exception {
+        startTestAppsWithCheck();
+        final Overview overview = mLauncher.goHome().switchToOverview();
+
+        final SelectModeButtons selectModeButtons;
+
+        if (mLauncher.isTablet() && mLauncher.isGridOnlyOverviewEnabled()) {
+            selectModeButtons = overview.getCurrentTask().tapMenu().tapSelectMenuItem();
+        } else {
+            selectModeButtons = overview.getOverviewActions().clickSelect();
+        }
+
+        assertTrue("Launcher internal state is not Overview Modal Task",
+                isInState(() -> LauncherState.OVERVIEW_MODAL_TASK));
+
+        selectModeButtons.dismissByEscKey();
+
+        assertTrue("Launcher internal state is not Overview",
+                isInState(() -> LauncherState.OVERVIEW));
+        overview.dismissByEscKey();
+        assertTrue("Launcher internal state is not Home",
+                isInState(() -> LauncherState.NORMAL));
+    }
+
+    @Test
+    public void testOpenOverviewWithActionPlusTabKeys() throws Exception {
+        startTestAppsWithCheck();
+        startAppFast(CALCULATOR_APP_PACKAGE); // Ensure Calculator is last opened app.
+        Workspace home = mLauncher.goHome();
+        assertTrue("Launcher state is not Home", isInState(() -> LauncherState.NORMAL));
+
+        Overview overview = home.openOverviewFromActionPlusTabKeyboardShortcut();
+
+        assertTrue("Launcher state is not Overview", isInState(() -> LauncherState.OVERVIEW));
+        overview.launchFocusedTaskByEnterKey(CALCULATOR_APP_PACKAGE); // Assert app is focused.
+    }
+
+    @Test
+    public void testOpenOverviewWithRecentsKey() throws Exception {
+        startTestAppsWithCheck();
+        startAppFast(CALCULATOR_APP_PACKAGE); // Ensure Calculator is last opened app.
+        Workspace home = mLauncher.goHome();
+        assertTrue("Launcher state is not Home", isInState(() -> LauncherState.NORMAL));
+
+        Overview overview = home.openOverviewFromRecentsKeyboardShortcut();
+
+        assertTrue("Launcher state is not Overview", isInState(() -> LauncherState.OVERVIEW));
+        overview.launchFocusedTaskByEnterKey(CALCULATOR_APP_PACKAGE); // Assert app is focused.
+    }
+
     private int getCurrentOverviewPage(Launcher launcher) {
         return launcher.<RecentsView>getOverviewPanel().getCurrentPage();
     }
@@ -210,11 +272,12 @@
         return launcher.<RecentsView>getOverviewPanel().getBottomRowTaskCountForTablet();
     }
 
-    @Ignore
+    // Staging; will be promoted to presubmit if stable
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
-    @ScreenRecord // b/238461765
     public void testSwitchToOverview() throws Exception {
         startTestAppsWithCheck();
         assertNotNull("Workspace.switchToOverview() returned null",
@@ -236,7 +299,9 @@
         }
     }
 
-    @Ignore
+    // Staging; will be promoted to presubmit if stable
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
@@ -266,6 +331,8 @@
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
+    @ScreenRecord // b/313464374
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325659406
     public void testQuickSwitchFromApp() throws Exception {
         startTestActivity(2);
         startTestActivity(3);
@@ -295,7 +362,6 @@
 
     @Test
     @TaskbarModeSwitch
-    @Ignore // b/314873201
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
@@ -309,7 +375,7 @@
             boolean isTransientTaskbar = mLauncher.isTransientTaskbar();
             // Expect task bar invisible when the launched app was the IME activity.
             LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
-            if (!isTransientTaskbar && isHardwareKeyboard()) {
+            if (!isTransientTaskbar && isHardwareKeyboard() && !mLauncher.isImeDocked()) {
                 launchedAppState.assertTaskbarVisible();
             } else {
                 launchedAppState.assertTaskbarHidden();
@@ -357,23 +423,19 @@
                 READ_DEVICE_CONFIG_PERMISSION);
         // Debug if we need to goHome to prevent wrong previous state b/315525621
         mLauncher.goHome();
-        assumeFalse(FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get());
-        mLauncher.getWorkspace().switchToAllApps();
-        mLauncher.pressBack();
-        mLauncher.getWorkspace();
+        mLauncher.getWorkspace().switchToAllApps().pressBackToWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
 
         startAppFast(CALCULATOR_APP_PACKAGE);
-        mLauncher.pressBack();
-        mLauncher.getWorkspace();
+        mLauncher.getLaunchedAppState().pressBackToWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
     }
 
     @Test
     @PortraitLandscape
     @TaskbarModeSwitch()
-    @PlatinumTest(focusArea = "launcher")
     @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
+    @Ignore("b/315376057")
     @ScreenRecord // b/309820115
     public void testOverviewForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
@@ -522,4 +584,25 @@
             mLauncher.getDevice().setOrientationNatural();
         }
     }
+
+    @Test
+    public void testExcludeFromRecents() throws Exception {
+        startExcludeFromRecentsTestActivity();
+        OverviewTask currentTask = getAndAssertLaunchedApp().switchToOverview().getCurrentTask();
+        // TODO(b/326565120): the expected content description shouldn't be null but for now there
+        // is a bug that causes it to sometimes be for excludeForRecents tasks.
+        assertTrue("Can't find ExcludeFromRecentsTestActivity after entering Overview from it",
+                currentTask.containsContentDescription("ExcludeFromRecents")
+                        || currentTask.containsContentDescription(null));
+        // Going home should clear out the excludeFromRecents task.
+        BaseOverview overview = mLauncher.goHome().switchToOverview();
+        if (overview.hasTasks()) {
+            currentTask = overview.getCurrentTask();
+            assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home",
+                    currentTask.containsContentDescription("ExcludeFromRecents")
+                            || currentTask.containsContentDescription(null));
+        } else {
+            // Presumably the test started with 0 tasks and remains that way after going home.
+        }
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 1e33635..2a54057 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,6 +16,7 @@
 package com.android.quickstep;
 
 
+import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
@@ -32,7 +33,6 @@
 import com.android.launcher3.tapl.Overview;
 import com.android.launcher3.tapl.Taskbar;
 import com.android.launcher3.tapl.TaskbarAppIcon;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
@@ -57,7 +57,6 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
-        AbstractLauncherUiTest.initialize(this);
 
         if (mLauncher.isTablet()) {
             mLauncher.enableBlockTimeout(true);
@@ -103,25 +102,36 @@
                 .getSplitScreenMenuItem()
                 .click();
 
-        mLauncher.getLaunchedAppState()
-                .getTaskbar()
-                .getAppIcon(CALCULATOR_APP_NAME)
-                .launchIntoSplitScreen();
+        if (enableSplitContextually()) {
+            // We're staying in all apps, use same instance
+            mLauncher.getAllApps()
+                    .getAppIcon(CALCULATOR_APP_NAME)
+                    .launchIntoSplitScreen();
+        } else {
+            // We're in overview, use taskbar instance
+            mLauncher.getLaunchedAppState()
+                    .getTaskbar()
+                    .getAppIcon(CALCULATOR_APP_NAME)
+                    .launchIntoSplitScreen();
+        }
     }
 
     @Test
-    public void testSaveAppPairMenuItemExistsOnSplitPair() throws Exception {
+    public void testSaveAppPairMenuItemOrActionExistsOnSplitPair() {
         assumeTrue("App pairs feature is currently not enabled, no test needed",
                 Flags.enableAppPairs());
 
         createAndLaunchASplitPair();
 
-        assertTrue("Save app pair menu item is missing",
-                mLauncher.goHome()
-                        .switchToOverview()
-                        .getCurrentTask()
-                        .tapMenu()
-                        .hasMenuItem("Save app pair"));
+        Overview overview = mLauncher.goHome().switchToOverview();
+        if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) {
+            assertTrue("Save app pair menu item is missing",
+                    overview.getCurrentTask()
+                            .tapMenu()
+                            .hasMenuItem("Save app pair"));
+        } else {
+            overview.getOverviewActions().assertHasAction("Save app pair");
+        }
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index f0683f9..ec245ee 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep;
 
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
 import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.PERSISTENT;
 import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT;
@@ -53,7 +55,7 @@
 
     @Override
     public void setUp() throws Exception {
-        mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+        mTaskbarWasInTransientMode = isTaskbarInTransientMode(getTargetContext());
         setTaskbarMode(mLauncher, isTaskbarTestModeTransient());
         super.setUp();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 3465f23..1556aa5 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -19,7 +19,6 @@
 import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
 
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.app.Instrumentation;
@@ -28,15 +27,13 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
 import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -47,12 +44,6 @@
     private static final String READ_DEVICE_CONFIG_PERMISSION =
             "android.permission.READ_DEVICE_CONFIG";
 
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        AbstractLauncherUiTest.initialize(this);
-    }
-
     @After
     public void tearDown() {
         mLauncher.setTrackpadGestureType(TrackpadGestureType.NONE);
@@ -77,7 +68,6 @@
     @NavigationModeSwitch(mode = ZERO_BUTTON)
     public void pressBack() throws Exception {
         assumeTrue(mLauncher.isTablet());
-        assumeFalse(FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get());
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
 
         try {
@@ -95,6 +85,7 @@
     @Test
     @PortraitLandscape
     @NavigationModeSwitch
+    @ScreenRecordRule.ScreenRecord // b/335674307
     public void switchToOverview() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index 7109bbf..4b20d60 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -24,7 +24,6 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
 import org.junit.Test;
@@ -68,7 +67,6 @@
 
     @Test
     @TaskbarModeSwitch(mode = TRANSIENT)
-    @PortraitLandscape
     public void testSwipeToStashAndUnstash() {
         getTaskbar().swipeDownToStash();
         mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
index f76e17a..208920a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
@@ -56,7 +56,6 @@
 import com.android.launcher3.testcomponent.ListViewService;
 import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
 import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.TestViewHelpers;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -93,8 +92,6 @@
 
     @Before
     public void setUp() throws Exception {
-        super.setUp();
-
         // Workaround for b/142351228, when there are no activities, the system may not destroy the
         // activity correctly for activities under instrumentation, which can leave two concurrent
         // activities, which changes the order in which the activities are cleaned up (overlapping
@@ -102,7 +99,7 @@
         // is started only after starting another app.
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
 
-        AbstractLauncherUiTest.initialize(this);
+        super.setUp();
 
         mModel = LauncherAppState.getInstance(mTargetContext).getModel();
         Executors.MODEL_EXECUTOR.submit(mModel.getModelDbController()::createEmptyDB).get();
@@ -193,16 +190,14 @@
             info.spanX = 2;
             info.spanY = 2;
             AtomicInteger widgetId = new AtomicInteger();
-            new FavoriteItemsTransaction(mTargetContext)
+
+            commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
                     .addItem(() -> {
                         LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, true);
                         item.screenId = FIRST_SCREEN_ID;
                         widgetId.set(item.appWidgetId);
                         return item;
-                    })
-                    .commitAndLoadHome(mLauncher);
-
-
+                    }));
 
             assertTrue("Widget is not present",
                     mLauncher.goHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
diff --git a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
index d744194..8eec903 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskViewTest.java
@@ -35,6 +35,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.views.TaskView;
 
@@ -47,7 +48,7 @@
 public class TaskViewTest {
 
     @Mock
-    private StatefulActivity mContext;
+    private QuickstepLauncher mContext;
     @Mock
     private Resources mResource;
     @Mock
diff --git a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index 1723844..ece67af 100644
--- a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -18,18 +18,38 @@
 
 import android.content.Context
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.apppairs.AppPairIcon
 import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
 import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.quickstep.TopTaskTracker
+import com.android.quickstep.TopTaskTracker.CachedTaskInfo
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.Task.TaskKey
 import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_30_70
 import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
 import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_70_30
+import java.util.function.Consumer
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class AppPairsControllerTest {
@@ -58,11 +78,37 @@
         appPairsController.encodeRank(STAGE_POSITION_BOTTOM_OR_RIGHT, SNAP_TO_70_30)
     }
 
+    @Mock lateinit var mockAppPairIcon: AppPairIcon
+    @Mock lateinit var mockTaskbarActivityContext: TaskbarActivityContext
+    @Mock lateinit var mockTopTaskTracker: TopTaskTracker
+    @Mock lateinit var mockCachedTaskInfo: CachedTaskInfo
+    @Mock lateinit var mockItemInfo1: ItemInfo
+    @Mock lateinit var mockItemInfo2: ItemInfo
+    @Mock lateinit var mockTask1: Task
+    @Mock lateinit var mockTask2: Task
+    @Mock lateinit var mockTaskKey1: TaskKey
+    @Mock lateinit var mockTaskKey2: TaskKey
+    @Captor lateinit var callbackCaptor: ArgumentCaptor<Consumer<Array<Task>>>
+
+    private lateinit var spyAppPairsController: AppPairsController
+
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
         appPairsController =
             AppPairsController(context, splitSelectStateController, statsLogManager)
+
+        // Stub methods on appPairsController so that they return mocks
+        spyAppPairsController = spy(appPairsController)
+        whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+        doReturn(mockTopTaskTracker).whenever(spyAppPairsController).topTaskTracker
+        whenever(mockTopTaskTracker.getCachedTopTask(any())).thenReturn(mockCachedTaskInfo)
+        whenever(mockTask1.getKey()).thenReturn(mockTaskKey1)
+        whenever(mockTask2.getKey()).thenReturn(mockTaskKey2)
+        doNothing().whenever(spyAppPairsController).launchAppPair(any(), any())
+        doNothing()
+            .whenever(spyAppPairsController)
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
     }
 
     @Test
@@ -144,4 +190,220 @@
             AppPairsController.convertRankToSnapPosition(right70),
         )
     }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldDoNothingWhenAppsAreAlreadyRunning() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 1 and 2 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(1, 2).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchAppPair and launchToSide were never called
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, never())
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp2ToRightWhenApp1IsOnLeft() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 1 and 3 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(1, 3).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_BOTTOM_OR_RIGHT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp2ToLeftWhenApp1IsOnRight() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 3 and 1 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(3, 1).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_TOP_OR_LEFT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp1ToRightWhenApp2IsOnLeft() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 2 and 3 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(2, 3).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_BOTTOM_OR_RIGHT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp1ToLeftWhenApp2IsOnRight() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 3 and 2 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(3, 2).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_TOP_OR_LEFT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchAppPairNormallyWhenUnrelatedPairIsOnScreen() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with apps 3 and 4 already on screen
+        whenever(mockTopTaskTracker.runningSplitTaskIds).thenReturn(arrayListOf(3, 4).toIntArray())
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchAppPair was called
+        verify(spyAppPairsController, times(1)).launchAppPair(any(), any())
+        verify(spyAppPairsController, never())
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp2ToRightWhenApp1IsFullscreen() {
+        /// Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with app 1 already on screen
+        whenever(mockCachedTaskInfo.taskId).thenReturn(1)
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_BOTTOM_OR_RIGHT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchApp1ToLeftWhenApp2IsFullscreen() {
+        /// Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with app 2 already on screen
+        whenever(mockCachedTaskInfo.taskId).thenReturn(2)
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchToSide was called with the correct arguments
+        verify(spyAppPairsController, never()).launchAppPair(any(), any())
+        verify(spyAppPairsController, times(1))
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), eq(STAGE_POSITION_TOP_OR_LEFT))
+    }
+
+    @Test
+    fun handleAppPairLaunchInApp_shouldLaunchAppPairNormallyWhenUnrelatedSingleAppIsFullscreen() {
+        // Test launching apps 1 and 2 from app pair
+        whenever(mockTaskKey1.getId()).thenReturn(1)
+        whenever(mockTaskKey2.getId()).thenReturn(2)
+        // ... with app 3 already on screen
+        whenever(mockCachedTaskInfo.taskId).thenReturn(3)
+
+        // Trigger app pair launch, capture and run callback from findLastActiveTasksAndRunCallback
+        spyAppPairsController.handleAppPairLaunchInApp(
+            mockAppPairIcon,
+            listOf(mockItemInfo1, mockItemInfo2)
+        )
+        verify(splitSelectStateController)
+            .findLastActiveTasksAndRunCallback(any(), any(), callbackCaptor.capture())
+        val callback: Consumer<Array<Task>> = callbackCaptor.value
+        callback.accept(arrayOf(mockTask1, mockTask2))
+
+        // Verify that launchAppPair was called
+        verify(spyAppPairsController, times(1)).launchAppPair(any(), any())
+        verify(spyAppPairsController, never())
+            .launchToSide(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/util/GestureExclusionManagerTest.kt b/quickstep/tests/src/com/android/quickstep/util/GestureExclusionManagerTest.kt
new file mode 100644
index 0000000..c190cfe
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/GestureExclusionManagerTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.graphics.Rect
+import android.graphics.Region
+import android.testing.AndroidTestingRunner
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.IWindowManager
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.Executors
+import com.android.quickstep.util.GestureExclusionManager.ExclusionListener
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyZeroInteractions
+
+/** Unit test for [GestureExclusionManager]. */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class GestureExclusionManagerTest {
+
+    @Mock private lateinit var windowManager: IWindowManager
+
+    @Mock private lateinit var listener1: ExclusionListener
+    @Mock private lateinit var listener2: ExclusionListener
+
+    private val r1 = Region().apply { union(Rect(0, 0, 100, 200)) }
+    private val r2 = Region().apply { union(Rect(200, 200, 500, 800)) }
+
+    private lateinit var underTest: GestureExclusionManager
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        underTest = GestureExclusionManager(windowManager)
+    }
+
+    @Test
+    fun addListener_registers() {
+        underTest.addListener(listener1)
+
+        awaitTasksCompleted()
+        verify(windowManager)
+            .registerSystemGestureExclusionListener(underTest.exclusionListener, DEFAULT_DISPLAY)
+    }
+
+    @Test
+    fun addListener_again_skips_register() {
+        underTest.addListener(listener1)
+        awaitTasksCompleted()
+        reset(windowManager)
+
+        underTest.addListener(listener2)
+
+        awaitTasksCompleted()
+        verifyZeroInteractions(windowManager)
+    }
+
+    @Test
+    fun removeListener_unregisters() {
+        underTest.addListener(listener1)
+        awaitTasksCompleted()
+        reset(windowManager)
+
+        underTest.removeListener(listener1)
+
+        awaitTasksCompleted()
+        verify(windowManager)
+            .unregisterSystemGestureExclusionListener(underTest.exclusionListener, DEFAULT_DISPLAY)
+    }
+
+    @Test
+    fun removeListener_again_skips_unregister() {
+        underTest.addListener(listener1)
+        underTest.addListener(listener2)
+        awaitTasksCompleted()
+        reset(windowManager)
+
+        underTest.removeListener(listener1)
+
+        awaitTasksCompleted()
+        verifyZeroInteractions(windowManager)
+    }
+
+    @Test
+    fun onSystemGestureExclusionChanged_dispatches_to_listeners() {
+        underTest.addListener(listener1)
+        underTest.addListener(listener2)
+        awaitTasksCompleted()
+
+        underTest.exclusionListener.onSystemGestureExclusionChanged(DEFAULT_DISPLAY, r1, r2)
+        awaitTasksCompleted()
+        verify(listener1).onGestureExclusionChanged(r1, r2)
+        verify(listener2).onGestureExclusionChanged(r1, r2)
+    }
+
+    @Test
+    fun addLister_dispatches_second_time() {
+        underTest.exclusionListener.onSystemGestureExclusionChanged(DEFAULT_DISPLAY, r1, r2)
+        awaitTasksCompleted()
+        underTest.addListener(listener1)
+        awaitTasksCompleted()
+        verifyZeroInteractions(listener1)
+
+        underTest.addListener(listener2)
+        awaitTasksCompleted()
+
+        verifyZeroInteractions(listener1)
+        verify(listener2).onGestureExclusionChanged(r1, r2)
+    }
+
+    private fun awaitTasksCompleted() {
+        Executors.UI_HELPER_EXECUTOR.submit<Any> { null }.get()
+        Executors.MAIN_EXECUTOR.submit<Any> { null }.get()
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 86018b1..68c9bf9 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -19,6 +19,7 @@
 
 import android.graphics.Bitmap
 import android.graphics.drawable.Drawable
+import android.view.ContextThemeWrapper
 import android.view.SurfaceControl.Transaction
 import android.view.View
 import android.window.TransitionInfo
@@ -26,6 +27,7 @@
 import com.android.launcher3.apppairs.AppPairIcon
 import com.android.launcher3.statehandlers.DepthController
 import com.android.launcher3.statemanager.StateManager
+import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.views.GroupedTaskView
 import com.android.quickstep.views.IconView
@@ -64,6 +66,8 @@
     private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
     // AppPairIcon
     private val mockAppPairIcon: AppPairIcon = mock()
+    private val mockContextThemeWrapper: ContextThemeWrapper = mock()
+    private val mockTaskbarActivityContext: TaskbarActivityContext = mock()
 
     // SplitSelectSource
     private val splitSelectSource: SplitConfigurationOptions.SplitSelectSource = mock()
@@ -247,9 +251,10 @@
     @Test
     fun playsAppropriateSplitLaunchAnimation_playsIconLaunchCorrectly() {
         val spySplitAnimationController = spy(splitAnimationController)
+        whenever(mockAppPairIcon.context).thenReturn(mockContextThemeWrapper)
         doNothing()
             .whenever(spySplitAnimationController)
-            .composeIconSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+            .composeIconSplitLaunchAnimator(any(), any(), any(), any())
 
         spySplitAnimationController.playSplitLaunchAnimation(
             null /* launchingTaskView */,
@@ -267,7 +272,33 @@
         )
 
         verify(spySplitAnimationController)
-            .composeIconSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+            .composeIconSplitLaunchAnimator(any(), any(), any(), any())
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsIconLaunchFromTaskbarContextCorrectly() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeScaleUpLaunchAnimation(any(), any(), any())
+
+        spySplitAnimationController.playSplitLaunchAnimation(
+            null /* launchingTaskView */,
+            mockAppPairIcon,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController).composeScaleUpLaunchAnimation(any(), any(), any())
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt
index c6c5be4..b4f1692 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt
@@ -60,6 +60,7 @@
     private val sampleShortcut = Intent()
     private val sampleShortcut2 = Intent()
     private val sampleItemInfo = ItemInfo()
+    private val sampleItemInfo2 = ItemInfo()
     private val samplePackage =
         AbstractLauncherUiTest.resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)
 
@@ -133,7 +134,7 @@
             null,
             INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        splitSelectDataHolder.setSecondTask(sampleTaskId, sampleItemInfo2)
         assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
     }
 
@@ -145,7 +146,7 @@
             null,
             null
         )
-        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser, sampleItemInfo2)
         assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
     }
 
@@ -158,7 +159,7 @@
             null,
             INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser, sampleItemInfo2)
         assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
     }
 
@@ -170,7 +171,7 @@
             sampleItemInfo,
             null
         )
-        splitSelectDataHolder.setSecondTask(sampleTaskId2)
+        splitSelectDataHolder.setSecondTask(sampleTaskId2, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_TASK_TASK)
@@ -194,7 +195,7 @@
             sampleItemInfo,
             null
         )
-        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_TASK_PENDINGINTENT)
@@ -218,7 +219,7 @@
             sampleItemInfo,
             null
         )
-        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_TASK_SHORTCUT)
@@ -243,7 +244,7 @@
             null,
             INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        splitSelectDataHolder.setSecondTask(sampleTaskId, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_PENDINGINTENT_TASK)
@@ -268,7 +269,7 @@
             null,
             INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        splitSelectDataHolder.setSecondTask(sampleTaskId, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_SHORTCUT_TASK)
@@ -293,7 +294,7 @@
             null,
             INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleIntent2, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleIntent2, sampleUser, sampleItemInfo2)
         val launchData = splitSelectDataHolder.getSplitLaunchData()
 
         assertEquals(launchData.splitLaunchType, SPLIT_PENDINGINTENT_PENDINGINTENT)
@@ -388,7 +389,7 @@
             null,
             null
         )
-        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser, sampleItemInfo2)
         splitSelectDataHolder.resetState()
         assertFalse(splitSelectDataHolder.isSplitSelectActive())
     }
@@ -402,7 +403,7 @@
                 null,
                 INVALID_TASK_ID
         )
-        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser, sampleItemInfo2)
         splitSelectDataHolder.resetState()
         assertFalse(splitSelectDataHolder.isSplitSelectActive())
     }
diff --git a/res/color-night-v31/folder_preview_dark.xml b/res/color-night-v31/folder_preview_dark.xml
index 644d61a..6dd20a1 100644
--- a/res/color-night-v31/folder_preview_dark.xml
+++ b/res/color-night-v31/folder_preview_dark.xml
@@ -16,5 +16,5 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
         android:color="@android:color/system_neutral1_900"
-        android:lStar="17" />
+        android:lStar="12" />
 </selector>
diff --git a/res/color-night-v31/material_color_surface_container_high.xml b/res/color-night-v31/material_color_surface_container_high.xml
index 002b88e..edd36fc 100644
--- a/res/color-night-v31/material_color_surface_container_high.xml
+++ b/res/color-night-v31/material_color_surface_container_high.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="17" />
 </selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_highest.xml b/res/color-night-v31/material_color_surface_container_highest.xml
index 002b88e..e54f953 100644
--- a/res/color-night-v31/material_color_surface_container_highest.xml
+++ b/res/color-night-v31/material_color_surface_container_highest.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="22" />
 </selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_low.xml b/res/color-night-v31/material_color_surface_container_low.xml
index 002b88e..40f0d4c 100644
--- a/res/color-night-v31/material_color_surface_container_low.xml
+++ b/res/color-night-v31/material_color_surface_container_low.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="10" />
 </selector>
\ No newline at end of file
diff --git a/res/color-night-v31/material_color_surface_container_lowest.xml b/res/color-night-v31/material_color_surface_container_lowest.xml
index 002b88e..24f559b 100644
--- a/res/color-night-v31/material_color_surface_container_lowest.xml
+++ b/res/color-night-v31/material_color_surface_container_lowest.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="12" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="4" />
 </selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_high.xml b/res/color-v31/material_color_surface_container_high.xml
index b031c08..a996d51 100644
--- a/res/color-v31/material_color_surface_container_high.xml
+++ b/res/color-v31/material_color_surface_container_high.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="92" />
 </selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_highest.xml b/res/color-v31/material_color_surface_container_highest.xml
index b031c08..e7a535a 100644
--- a/res/color-v31/material_color_surface_container_highest.xml
+++ b/res/color-v31/material_color_surface_container_highest.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="90" />
 </selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_low.xml b/res/color-v31/material_color_surface_container_low.xml
index b031c08..b8fe01e 100644
--- a/res/color-v31/material_color_surface_container_low.xml
+++ b/res/color-v31/material_color_surface_container_low.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="96" />
 </selector>
\ No newline at end of file
diff --git a/res/color-v31/material_color_surface_container_lowest.xml b/res/color-v31/material_color_surface_container_lowest.xml
index 674fc73..25e8666 100644
--- a/res/color-v31/material_color_surface_container_lowest.xml
+++ b/res/color-v31/material_color_surface_container_lowest.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@android:color/system_neutral1_500" android:lStar="94" />
+    <item android:color="@android:color/system_neutral1_500" android:lStar="100" />
 </selector>
\ No newline at end of file
diff --git a/res/color/taskbar_background_dark.xml b/res/color/taskbar_background_dark.xml
new file mode 100644
index 0000000..0727b8a
--- /dev/null
+++ b/res/color/taskbar_background_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!-- Should be the same as in packages/apps/Launcher3/res/color-night-v31/taskbar_background.xml -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!--  Want to use @android:color/system_neutral1_500, but that causes build errors  -->
+    <item android:color="#76777D" android:lStar="6" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_search_button.xml b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_search_button.xml
index eb5b41e..8510c66 100644
--- a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_search_button.xml
+++ b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_search_button.xml
@@ -20,17 +20,7 @@
     android:viewportHeight="52"
     android:viewportWidth="52">
 
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M18.25,17.75m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M18.25,34.25m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M34.75,17.75m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:fillType="evenOdd"
-      android:pathData="M37.75,34.25C37.75,32.6 36.4,31.25 34.75,31.25C33.1,31.25 31.75,32.6 31.75,34.25C31.75,35.9 33.1,37.25 34.75,37.25C36.4,37.25 37.75,35.9 37.75,34.25ZM28.75,34.25C28.75,30.935 31.435,28.25 34.75,28.25C38.065,28.25 40.75,30.935 40.75,34.25C40.75,35.361 40.449,36.401 39.923,37.292L44.5,41.884L42.386,43.999L37.795,39.422C36.902,39.948 35.862,40.25 34.75,40.25C31.435,40.25 28.75,37.565 28.75,34.25Z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M41.46,42.463L37.063,38.104C36.633,38.398 36.166,38.621 35.663,38.773C35.16,38.925 34.634,39.001 34.084,39.001C32.572,39.001 31.279,38.464 30.203,37.389C29.126,36.314 28.588,35.021 28.588,33.512C28.588,32.002 29.126,30.71 30.201,29.636C31.276,28.562 32.568,28.025 34.078,28.025C35.588,28.025 36.879,28.562 37.953,29.635C39.027,30.708 39.564,31.999 39.564,33.506C39.564,34.071 39.485,34.604 39.325,35.108C39.165,35.611 38.938,36.078 38.644,36.509L43.026,40.882L41.46,42.463ZM18.045,39.015C16.538,39.015 15.248,38.479 14.174,37.404C13.101,36.331 12.564,35.031 12.564,33.506C12.564,31.999 13.101,30.708 14.174,29.635C15.248,28.562 16.538,28.025 18.045,28.025C19.57,28.025 20.87,28.562 21.944,29.635C23.018,30.708 23.555,31.999 23.555,33.506C23.555,35.031 23.018,36.331 21.944,37.404C20.87,38.479 19.57,39.015 18.045,39.015ZM34.084,36.766C34.972,36.766 35.733,36.45 36.365,35.819C36.998,35.189 37.314,34.417 37.314,33.506C37.314,32.618 36.998,31.857 36.365,31.224C35.733,30.591 34.972,30.275 34.084,30.275C33.172,30.275 32.401,30.591 31.77,31.224C31.139,31.857 30.824,32.618 30.824,33.506C30.824,34.417 31.139,35.189 31.77,35.819C32.401,36.45 33.172,36.766 34.084,36.766ZM18.045,23.006C16.538,23.006 15.248,22.469 14.174,21.395C13.101,20.321 12.564,19.021 12.564,17.496C12.564,15.989 13.101,14.699 14.174,13.626C15.248,12.552 16.538,12.016 18.045,12.016C19.57,12.016 20.87,12.552 21.944,13.626C23.018,14.699 23.555,15.989 23.555,17.496C23.555,19.021 23.018,20.321 21.944,21.395C20.87,22.469 19.57,23.006 18.045,23.006ZM34.084,23.006C32.559,23.006 31.259,22.469 30.185,21.395C29.111,20.321 28.574,19.021 28.574,17.496C28.574,15.989 29.111,14.699 30.185,13.626C31.259,12.552 32.559,12.016 34.084,12.016C35.591,12.016 36.881,12.552 37.954,13.626C39.028,14.699 39.564,15.989 39.564,17.496C39.564,19.021 39.028,20.321 37.954,21.395C36.881,22.469 35.591,23.006 34.084,23.006Z" />
 </vector>
\ No newline at end of file
diff --git a/res/drawable-v31/bg_deferred_app_widget.xml b/res/drawable-v31/bg_deferred_app_widget.xml
deleted file mode 100644
index a08998d..0000000
--- a/res/drawable-v31/bg_deferred_app_widget.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2021 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:inset="8dp">
-    <shape android:shape="rectangle">
-        <corners android:radius="@android:dimen/system_app_widget_background_radius" />
-        <solid android:color="#77000000" />
-    </shape>
-</inset>
diff --git a/res/drawable/bg_deferred_app_widget.xml b/res/drawable/bg_deferred_app_widget.xml
deleted file mode 100644
index 07bae48..0000000
--- a/res/drawable/bg_deferred_app_widget.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<inset
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:inset="8dp">
-    <color android:color="#77000000" />
-</inset>
diff --git a/res/drawable/bg_ps_header.xml b/res/drawable/bg_ps_header.xml
index 526bb5a..da31445 100644
--- a/res/drawable/bg_ps_header.xml
+++ b/res/drawable/bg_ps_header.xml
@@ -14,9 +14,13 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <corners android:radius="@dimen/ps_container_corner_radius" />
-    <solid android:color="?attr/materialColorSurfaceContainerHigh" />
-</shape>
\ No newline at end of file
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/accent_ripple_color">
+    <item>
+        <shape xmlns:android="http://schemas.android.com/apk/res/android"
+            android:shape="rectangle">
+            <corners android:radius="@dimen/ps_container_corner_radius" />
+            <solid android:color="?attr/materialColorSurfaceContainerHigh" />
+        </shape>
+    </item>
+</ripple>
diff --git a/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
index c502178..379e0e5 100644
--- a/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
+++ b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
@@ -17,6 +17,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:shape="rectangle" >
-    <solid android:color="?androidprv:attr/colorSurfaceVariant"/>
+    <solid android:color="?androidprv:attr/materialColorOutlineVariant"/>
     <corners android:radius="@dimen/bottom_sheet_handle_corner_radius" />
 </shape>
diff --git a/res/drawable/encrypted_24px.xml b/res/drawable/encrypted_24px.xml
deleted file mode 100644
index cf4d2df..0000000
--- a/res/drawable/encrypted_24px.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="960"
-    android:viewportHeight="960"
-    android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M420,600L540,600L517,471Q537,461 548.5,442Q560,423 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,423 411.5,442Q423,461 443,471L420,600ZM480,880Q341,845 250.5,720.5Q160,596 160,444L160,200L480,80L800,200L800,444Q800,596 709.5,720.5Q619,845 480,880ZM480,796Q584,763 652,664Q720,565 720,444L720,255L480,165L240,255L240,444Q240,565 308,664Q376,763 480,796ZM480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
-</vector>
diff --git a/res/drawable/ic_allapps_search.xml b/res/drawable/ic_allapps_search.xml
index 0c3ab78..53b4f91 100644
--- a/res/drawable/ic_allapps_search.xml
+++ b/res/drawable/ic_allapps_search.xml
@@ -18,8 +18,9 @@
     android:height="24dp"
     android:viewportHeight="24.0"
     android:viewportWidth="24.0"
-    android:autoMirrored="true">
+    android:autoMirrored="true"
+    android:tint="?attr/widgetPickerSearchTextColor">
     <path
-        android:fillColor="?attr/widgetPickerSearchTextColor"
+        android:fillColor="#FFFFFF"
         android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
 </vector>
diff --git a/res/drawable/ic_info_no_shadow.xml b/res/drawable/ic_info_no_shadow.xml
index 7c43779..29a81bd 100644
--- a/res/drawable/ic_info_no_shadow.xml
+++ b/res/drawable/ic_info_no_shadow.xml
@@ -18,7 +18,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="?android:attr/textColorPrimary">
+        android:tint="?attr/materialColorOnSurface">
 
     <path
         android:fillColor="@android:color/white"
diff --git a/res/drawable/ic_install_no_shadow.xml b/res/drawable/ic_install_no_shadow.xml
index eaad0de..6e0125a 100644
--- a/res/drawable/ic_install_no_shadow.xml
+++ b/res/drawable/ic_install_no_shadow.xml
@@ -18,7 +18,7 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24"
-    android:tint="?android:attr/textColorPrimary">
+    android:tint="?attr/materialColorOnSurface">
 
     <path
         android:fillColor="@android:color/white"
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
new file mode 100644
index 0000000..a16d35a
--- /dev/null
+++ b/res/drawable/ic_install_to_private.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/materialColorOnSurface">
+
+    <group>
+        <clip-path
+            android:pathData="M0,0h24v24h-24z"/>
+        <path
+            android:pathData="M12.001,1.999L4.001,4.999V11.089C4.001,16.139 7.411,20.849 12.001,21.999C16.591,20.849 20.001,16.139 20.001,11.089V4.999L12.001,1.999ZM18.001,11.089C18.001,15.089 15.451,18.789 12.001,19.919C8.551,18.789 6.001,15.099 6.001,11.089V6.389L12.001,4.139L18.001,6.389V11.089Z"
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"/>
+        <path
+            android:pathData="M8.501,9.5C8.501,11.08 9.561,12.41 11.001,12.84V18H13.001V17H15.001V15H13.001V12.84C14.441,12.41 15.501,11.09 15.501,9.5C15.501,7.57 13.931,6 12.001,6C10.071,6 8.501,7.57 8.501,9.5ZM13.501,9.5C13.501,10.33 12.831,11 12.001,11C11.171,11 10.501,10.33 10.501,9.5C10.501,8.67 11.171,8 12.001,8C12.831,8 13.501,8.67 13.501,9.5Z"
+            android:fillColor="@android:color/white"
+            android:fillType="evenOdd"/>
+    </group>
+</vector>
diff --git a/res/drawable/ic_lock.xml b/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..055e6b4
--- /dev/null
+++ b/res/drawable/ic_lock.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="20dp"
+    android:height="20dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960">
+    <path
+        android:fillColor="?attr/materialColorOnPrimaryFixed"
+        android:pathData="M263.72,864Q234,864 213,842.85Q192,821.7 192,792L192,408Q192,378.3 213.15,357.15Q234.3,336 264,336L288,336L288,240Q288,160.32 344.23,104.16Q400.45,48 480.23,48Q560,48 616,104.16Q672,160.32 672,240L672,336L696,336Q725.7,336 746.85,357.15Q768,378.3 768,408L768,792Q768,821.7 746.84,842.85Q725.68,864 695.96,864L263.72,864ZM264,792L696,792Q696,792 696,792Q696,792 696,792L696,408Q696,408 696,408Q696,408 696,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792ZM480.21,672Q510,672 531,650.79Q552,629.58 552,599.79Q552,570 530.79,549Q509.58,528 479.79,528Q450,528 429,549.21Q408,570.42 408,600.21Q408,630 429.21,651Q450.42,672 480.21,672ZM360,336L600,336L600,240Q600,190 565,155Q530,120 480,120Q430,120 395,155Q360,190 360,240L360,336ZM264,792Q264,792 264,792Q264,792 264,792L264,408Q264,408 264,408Q264,408 264,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792L264,792Z"/>
+</vector>
diff --git a/res/drawable/icon_menu_background.xml b/res/drawable/ic_plus.xml
similarity index 61%
copy from res/drawable/icon_menu_background.xml
copy to res/drawable/ic_plus.xml
index 8a95c3e..3ab926a 100644
--- a/res/drawable/icon_menu_background.xml
+++ b/res/drawable/ic_plus.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
+<!-- Copyright (C) 2024 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:shape="rectangle">
-    <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
-</shape>
\ No newline at end of file
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="19dp"
+    android:height="18dp"
+    android:viewportWidth="19"
+    android:viewportHeight="18">
+  <path
+      android:pathData="M15.5,9.75H10.25V15H8.75V9.75H3.5V8.25H8.75V3H10.25V8.25H15.5V9.75Z"
+      android:fillColor="#ffffff"/>
+</vector>
diff --git a/res/drawable/ic_private_profile_app_scroller_badge.xml b/res/drawable/ic_private_profile_app_scroller_badge.xml
new file mode 100644
index 0000000..ede42b9
--- /dev/null
+++ b/res/drawable/ic_private_profile_app_scroller_badge.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+    android:viewportWidth="32"
+    android:viewportHeight="32"
+    android:width="32dp"
+    android:height="32dp">
+    <path
+        android:pathData="M16.0007 2.66602L5.33398 6.66602V14.786C5.33398 21.5194 9.88065 27.7993 16.0007 29.3327C22.1207 27.7993 26.6673 21.5194 26.6673 14.786V6.66602L16.0007 2.66602ZM20.0007 19.9993V22.666H17.334V23.9993H14.6673V17.1193C12.7473 16.546 11.334 14.786 11.334 12.666C11.334 10.0927 13.4273 7.99935 16.0007 7.99935C18.574 7.99935 20.6673 10.0927 20.6673 12.666C20.6673 14.7727 19.254 16.546 17.334 17.1193V19.9993H20.0007Z"
+        android:fillType="evenOdd"
+        android:fillColor="?android:attr/textColorPrimaryInverse" />
+    <path
+        android:pathData="M16 14.666C17.1046 14.666 18 13.7706 18 12.666C18 11.5614 17.1046 10.666 16 10.666C14.8954 10.666 14 11.5614 14 12.666C14 13.7706 14.8954 14.666 16 14.666Z"
+        android:fillColor="?android:attr/textColorPrimaryInverse" />
+</vector>
diff --git a/res/drawable/ic_private_space_with_background.xml b/res/drawable/ic_private_space_with_background.xml
new file mode 100644
index 0000000..cb37c9a
--- /dev/null
+++ b/res/drawable/ic_private_space_with_background.xml
@@ -0,0 +1,32 @@
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:width="48dp"
+    android:height="48dp">
+    <path
+        android:pathData="M48 24A24 24 0 0 1 0 24A24 24 0 0 1 48 24Z"
+        android:fillColor="?androidprv:attr/materialColorSurfaceContainerLowest" />
+    <path
+        android:pathData="M24.0021 10.6641L13.3354 14.6641V22.7841C13.3354 29.5174 17.8821 35.7974 24.0021 37.3307C30.1221 35.7974 34.6688 29.5174 34.6688 22.7841V14.6641L24.0021 10.6641ZM32.0021 22.7841C32.0021 28.1174 28.6021 33.0507 24.0021 34.5574C19.4021 33.0507 16.0021 28.1307 16.0021 22.7841V16.5174L24.0021 13.5174L32.0021 16.5174V22.7841Z"
+        android:fillType="evenOdd"
+        android:fillColor="?attr/materialColorOnSurface" />
+    <path
+        android:pathData="M19.3354 20.6657C19.3354 22.7724 20.7488 24.5457 22.6688 25.119V31.999H25.3354V30.6657H28.0021V27.999H25.3354V25.119C27.2554 24.5457 28.6688 22.7857 28.6688 20.6657C28.6688 18.0924 26.5754 15.999 24.0021 15.999C21.4288 15.999 19.3354 18.0924 19.3354 20.6657ZM26.0021 20.6657C26.0021 21.7724 25.1088 22.6657 24.0021 22.6657C22.8954 22.6657 22.0021 21.7724 22.0021 20.6657C22.0021 19.559 22.8954 18.6657 24.0021 18.6657C25.1088 18.6657 26.0021 19.559 26.0021 20.6657Z"
+        android:fillType="evenOdd"
+        android:fillColor="?attr/materialColorOnSurface" />
+</vector>
diff --git a/res/drawable/bg_ps_settings_button.xml b/res/drawable/ic_ps_settings.xml
similarity index 93%
rename from res/drawable/bg_ps_settings_button.xml
rename to res/drawable/ic_ps_settings.xml
index c06e0c0..47edeb8 100644
--- a/res/drawable/bg_ps_settings_button.xml
+++ b/res/drawable/ic_ps_settings.xml
@@ -15,13 +15,10 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="@dimen/ps_button_height"
+    android:width="@dimen/ps_button_width"
     android:height="@dimen/ps_button_height"
     android:viewportWidth="40"
     android:viewportHeight="40">
-    <path
-        android:pathData="M20,0L20,0A20,20 0,0 1,40 20L40,20A20,20 0,0 1,20 40L20,40A20,20 0,0 1,0 20L0,20A20,20 0,0 1,20 0z"
-        android:fillColor="?attr/materialColorSurfaceBright"/>
     <group>
         <clip-path
             android:pathData="M10,10h20v20h-20z"/>
diff --git a/res/drawable/ic_taskbar_all_apps_search_button.xml b/res/drawable/ic_taskbar_all_apps_search_button.xml
index 5b4b01b..49667b7 100644
--- a/res/drawable/ic_taskbar_all_apps_search_button.xml
+++ b/res/drawable/ic_taskbar_all_apps_search_button.xml
@@ -19,17 +19,7 @@
     android:autoMirrored="true"
     android:viewportHeight="44"
     android:viewportWidth="44">
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M14.333,14.333m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M14.333,28.997m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M28.999,14.333m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:fillType="evenOdd"
-      android:pathData="M31.668,29.005C31.668,27.538 30.468,26.338 29.001,26.338C27.535,26.338 26.335,27.538 26.335,29.005C26.335,30.472 27.535,31.672 29.001,31.672C30.468,31.672 31.668,30.472 31.668,29.005ZM23.668,29.005C23.668,26.059 26.055,23.672 29.001,23.672C31.948,23.672 34.335,26.059 34.335,29.005C34.335,29.992 34.067,30.917 33.6,31.709L37.669,35.791L35.789,37.671L31.708,33.602C30.915,34.07 29.989,34.339 29.001,34.339C26.055,34.339 23.668,31.952 23.668,29.005Z" />
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M35.351,36.744L31.443,32.869C31.06,33.131 30.645,33.329 30.198,33.464C29.751,33.599 29.283,33.667 28.794,33.667C27.451,33.667 26.301,33.189 25.344,32.233C24.388,31.278 23.91,30.129 23.91,28.787C23.91,27.445 24.387,26.297 25.343,25.343C26.299,24.388 27.447,23.91 28.789,23.91C30.131,23.91 31.279,24.388 32.234,25.341C33.189,26.296 33.666,27.442 33.666,28.782C33.666,29.284 33.595,29.759 33.453,30.206C33.311,30.653 33.11,31.069 32.848,31.451L36.743,35.339L35.351,36.744ZM14.538,33.68C13.198,33.68 12.051,33.202 11.097,32.248C10.143,31.293 9.666,30.138 9.666,28.782C9.666,27.442 10.143,26.296 11.097,25.341C12.051,24.388 13.198,23.91 14.538,23.91C15.893,23.91 17.049,24.388 18.003,25.341C18.958,26.296 19.435,27.442 19.435,28.782C19.435,30.138 18.958,31.293 18.003,32.248C17.049,33.202 15.893,33.68 14.538,33.68ZM28.794,31.68C29.584,31.68 30.26,31.399 30.822,30.839C31.385,30.278 31.666,29.593 31.666,28.782C31.666,27.992 31.385,27.316 30.822,26.754C30.26,26.192 29.584,25.91 28.794,25.91C27.984,25.91 27.298,26.192 26.738,26.754C26.177,27.316 25.897,27.992 25.897,28.782C25.897,29.593 26.177,30.278 26.738,30.839C27.298,31.399 27.984,31.68 28.794,31.68ZM14.538,19.449C13.198,19.449 12.051,18.972 11.097,18.017C10.143,17.062 9.666,15.907 9.666,14.552C9.666,13.212 10.143,12.065 11.097,11.111C12.051,10.157 13.198,9.68 14.538,9.68C15.893,9.68 17.049,10.157 18.003,11.111C18.958,12.065 19.435,13.212 19.435,14.552C19.435,15.907 18.958,17.062 18.003,18.017C17.049,18.972 15.893,19.449 14.538,19.449ZM28.794,19.449C27.439,19.449 26.284,18.972 25.329,18.017C24.374,17.062 23.897,15.907 23.897,14.552C23.897,13.212 24.374,12.065 25.329,11.111C26.284,10.157 27.439,9.68 28.794,9.68C30.134,9.68 31.281,10.157 32.235,11.111C33.189,12.065 33.666,13.212 33.666,14.552C33.666,15.907 33.189,17.062 32.235,18.017C31.281,18.972 30.134,19.449 28.794,19.449Z" />
 </vector>
diff --git a/res/drawable/ic_transient_taskbar_all_apps_search_button.xml b/res/drawable/ic_transient_taskbar_all_apps_search_button.xml
index 85a17f5..b422995 100644
--- a/res/drawable/ic_transient_taskbar_all_apps_search_button.xml
+++ b/res/drawable/ic_transient_taskbar_all_apps_search_button.xml
@@ -19,17 +19,8 @@
     android:autoMirrored="true"
     android:viewportHeight="48"
     android:viewportWidth="48">
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M16.833,16.333m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M16.833,30.997m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:pathData="M31.499,16.333m-5.333,0a5.333,5.333 0,1 1,10.667 0a5.333,5.333 0,1 1,-10.667 0" />
-  <path
-      android:fillColor="#FF000000"
-      android:fillType="evenOdd"
-      android:pathData="M34.168,31.005C34.168,29.538 32.968,28.338 31.501,28.338C30.035,28.338 28.835,29.538 28.835,31.005C28.835,32.472 30.035,33.672 31.501,33.672C32.968,33.672 34.168,32.472 34.168,31.005ZM26.168,31.005C26.168,28.059 28.555,25.672 31.501,25.672C34.448,25.672 36.835,28.059 36.835,31.005C36.835,31.992 36.567,32.917 36.1,33.709L40.169,37.791L38.289,39.671L34.208,35.602C33.415,36.07 32.489,36.339 31.501,36.339C28.555,36.339 26.168,33.952 26.168,31.005Z" />
-</vector>
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M38.351,38.744L34.443,34.869C34.06,35.131 33.645,35.329 33.198,35.464C32.751,35.599 32.283,35.667 31.794,35.667C30.451,35.667 29.301,35.189 28.344,34.233C27.388,33.278 26.91,32.129 26.91,30.787C26.91,29.445 27.387,28.297 28.343,27.343C29.299,26.388 30.447,25.91 31.789,25.91C33.131,25.91 34.279,26.388 35.234,27.341C36.189,28.296 36.666,29.442 36.666,30.782C36.666,31.284 36.595,31.759 36.453,32.206C36.311,32.653 36.11,33.069 35.848,33.451L39.743,37.339L38.351,38.744ZM17.538,35.68C16.198,35.68 15.051,35.202 14.097,34.248C13.143,33.293 12.666,32.138 12.666,30.782C12.666,29.442 13.143,28.296 14.097,27.341C15.051,26.388 16.198,25.91 17.538,25.91C18.893,25.91 20.049,26.388 21.003,27.341C21.958,28.296 22.435,29.442 22.435,30.782C22.435,32.138 21.958,33.293 21.003,34.248C20.049,35.202 18.893,35.68 17.538,35.68ZM31.794,33.68C32.584,33.68 33.26,33.399 33.822,32.839C34.385,32.278 34.666,31.593 34.666,30.782C34.666,29.992 34.385,29.316 33.822,28.754C33.26,28.192 32.584,27.91 31.794,27.91C30.984,27.91 30.298,28.192 29.738,28.754C29.177,29.316 28.897,29.992 28.897,30.782C28.897,31.593 29.177,32.278 29.738,32.839C30.298,33.399 30.984,33.68 31.794,33.68ZM17.538,21.449C16.198,21.449 15.051,20.972 14.097,20.017C13.143,19.062 12.666,17.907 12.666,16.552C12.666,15.212 13.143,14.065 14.097,13.111C15.051,12.157 16.198,11.68 17.538,11.68C18.893,11.68 20.049,12.157 21.003,13.111C21.958,14.065 22.435,15.212 22.435,16.552C22.435,17.907 21.958,19.062 21.003,20.017C20.049,20.972 18.893,21.449 17.538,21.449ZM31.794,21.449C30.439,21.449 29.284,20.972 28.329,20.017C27.374,19.062 26.897,17.907 26.897,16.552C26.897,15.212 27.374,14.065 28.329,13.111C29.284,12.157 30.439,11.68 31.794,11.68C33.134,11.68 34.281,12.157 35.235,13.111C36.189,14.065 36.666,15.212 36.666,16.552C36.666,17.907 36.189,19.062 35.235,20.017C34.281,20.972 33.134,21.449 31.794,21.449Z" />
+</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml
index fbabdd2..6200054 100644
--- a/res/drawable/ic_uninstall_no_shadow.xml
+++ b/res/drawable/ic_uninstall_no_shadow.xml
@@ -18,7 +18,7 @@
         android:height="20dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
-        android:tint="?android:attr/textColorPrimary" >
+        android:tint="?attr/materialColorOnSurface" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4H15z M17,19H7V6h10V19z" />
diff --git a/res/drawable/icon_menu_background_corners.xml b/res/drawable/icon_menu_background_corners.xml
deleted file mode 100644
index 16e3fe2..0000000
--- a/res/drawable/icon_menu_background_corners.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:shape="rectangle">
-    <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
-    <corners android:radius="@dimen/task_thumbnail_icon_menu_corner_radius" />
-</shape>
\ No newline at end of file
diff --git a/res/drawable/icon_menu_elevation_background.xml b/res/drawable/icon_menu_elevation_background.xml
deleted file mode 100644
index 16e3fe2..0000000
--- a/res/drawable/icon_menu_elevation_background.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:shape="rectangle">
-    <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
-    <corners android:radius="@dimen/task_thumbnail_icon_menu_corner_radius" />
-</shape>
\ No newline at end of file
diff --git a/res/drawable/notification_circle.xml b/res/drawable/notification_circle.xml
deleted file mode 100644
index 65fbaea..0000000
--- a/res/drawable/notification_circle.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-
-    <solid android:color="?attr/popupNotificationDotColor"/>
-
-    <size
-        android:width="@dimen/notification_circle_icon_size"
-        android:height="@dimen/notification_circle_icon_size"/>
-</shape>
\ No newline at end of file
diff --git a/res/drawable/page_indicator.xml b/res/drawable/page_indicator.xml
index c0ccc49..d4cb13f 100644
--- a/res/drawable/page_indicator.xml
+++ b/res/drawable/page_indicator.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/folderPaginationColor"/>
+    <solid android:color="?attr/pageIndicatorDotColor"/>
     <size android:width="@dimen/page_indicator_size" android:height="@dimen/page_indicator_size"/>
 </shape>
\ No newline at end of file
diff --git a/res/drawable/private_space_app_divider.xml b/res/drawable/private_space_app_divider.xml
new file mode 100644
index 0000000..7d069ef
--- /dev/null
+++ b/res/drawable/private_space_app_divider.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="?attr/materialColorOutlineVariant"/>
+    <size android:height="1dp" />
+</shape>
\ No newline at end of file
diff --git a/res/drawable/private_space_install_app_icon.xml b/res/drawable/private_space_install_app_icon.xml
new file mode 100644
index 0000000..4c167ba
--- /dev/null
+++ b/res/drawable/private_space_install_app_icon.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="60dp"
+    android:height="60dp"
+    android:viewportWidth="60"
+    android:viewportHeight="60">
+    <group>
+        <clip-path
+            android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z" />
+        <path
+            android:pathData="M30 0H30A30 30 0 0 1 60 30V30A30 30 0 0 1 30 60H30A30 30 0 0 1 0 30V30A30 30 0 0 1 30 0Z"
+            android:fillColor="@color/material_color_surface_bright" />
+        <path
+            android:pathData="M29 31h-6v-2h6v-6h2v6h6v2h-6v6h-2v-6Z"
+            android:fillColor="@color/material_color_on_surface_variant" />
+    </group>
+</vector>
diff --git a/res/drawable/ps_lock_background.xml b/res/drawable/ps_lock_background.xml
new file mode 100644
index 0000000..0be83db
--- /dev/null
+++ b/res/drawable/ps_lock_background.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/accent_ripple_color">
+    <item>
+        <inset android:inset="4dp">
+            <shape android:shape="rectangle">
+                <corners android:radius="@dimen/ps_lock_corner_radius" />
+                <solid android:color="?attr/materialColorPrimaryFixedDim" />
+                <padding
+                    android:left="@dimen/ps_lock_button_background_padding"
+                    android:right="@dimen/ps_lock_button_background_padding" />
+            </shape>
+        </inset>
+    </item>
+</ripple>
diff --git a/res/drawable/ps_settings_background.xml b/res/drawable/ps_settings_background.xml
new file mode 100644
index 0000000..b0c6b5b
--- /dev/null
+++ b/res/drawable/ps_settings_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:inset="4dp">
+    <shape android:shape="rectangle">
+        <corners android:radius="@dimen/ps_lock_corner_radius" />
+        <solid android:color="?attr/materialColorSurfaceBright" />
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/widget_cell_add_button_background.xml b/res/drawable/widget_cell_add_button_background.xml
new file mode 100644
index 0000000..860d1cd
--- /dev/null
+++ b/res/drawable/widget_cell_add_button_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item>
+            <shape android:shape="rectangle">
+                <corners
+                    android:radius="50dp"/>
+                <solid android:color="?attr/widgetPickerAddButtonBackgroundColor" />
+            </shape>
+        </item>
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/widget_internal_focus_bg.xml b/res/drawable/widget_internal_focus_bg.xml
index 4d4bea6..b1f45a4 100644
--- a/res/drawable/widget_internal_focus_bg.xml
+++ b/res/drawable/widget_internal_focus_bg.xml
@@ -23,6 +23,7 @@
     <item android:state_selected="true">
         <shape android:shape="rectangle">
             <stroke android:color="#fff" android:width="2dp" />
+            <corners android:radius="@dimen/focus_outline_radius" />
         </shape>
     </item>
 </selector>
\ No newline at end of file
diff --git a/res/drawable/widget_picker_preview_pane_scroll_thumb.xml b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
new file mode 100644
index 0000000..24f90b0
--- /dev/null
+++ b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!--
+A variation of material's scrollbar_handle_material.xml that has paddings to make it smaller.
+ScrollView's "insideInsets" / "insideOverlay" styles don't consider corner radius applied to scroll
+views, so we apply matching padding to the thumb to align it.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:bottom="@dimen/widget_list_top_bottom_corner_radius"
+        android:top="@dimen/widget_list_top_bottom_corner_radius">
+        <shape
+            android:shape="rectangle"
+            android:tint="?android:attr/colorControlNormal">
+            <solid android:color="#84ffffff" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index 478b887..6be33e8 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -19,9 +19,6 @@
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
             <solid android:color="@color/work_fab_bg_color" />
-            <padding
-                android:left="@dimen/work_profile_footer_padding"
-                android:right="@dimen/work_profile_footer_padding" />
         </shape>
     </item>
 </ripple>
diff --git a/res/layout/develop_options_edit_text.xml b/res/layout/develop_options_edit_text.xml
new file mode 100644
index 0000000..5e44228
--- /dev/null
+++ b/res/layout/develop_options_edit_text.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<com.android.launcher3.ExtendedEditText
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:minWidth="100dp"
+    android:inputType="numberSigned"
+    android:id="@+id/pref_edit_text"
+    android:selectAllOnFocus="true"
+    android:imeOptions="actionDone"
+    android:maxLines="1" />
\ No newline at end of file
diff --git a/res/layout/developer_options_top_bar.xml b/res/layout/developer_options_top_bar.xml
index 1b138ea..ca46311 100644
--- a/res/layout/developer_options_top_bar.xml
+++ b/res/layout/developer_options_top_bar.xml
@@ -11,16 +11,17 @@
         android:layout_weight="1"
         android:layout_height="wrap_content"
         android:layout_marginHorizontal="@dimen/developer_options_filter_margins"
+        android:background="@drawable/rounded_action_button"
+        android:layout_marginTop="4dp"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp"
+        android:padding="12dp"
+        android:drawableStart="@drawable/ic_allapps_search"
+        android:drawableTint="?android:attr/textColorSecondary"
+        android:drawablePadding="8dp"
         android:hint="@string/developer_options_filter_hint"
         android:inputType="text"
         android:maxLines="1"
         android:imeOptions="actionDone"
         />
-    <Button
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:gravity="center_vertical"
-        android:text="Apply"
-        android:visibility="invisible"
-        android:id="@+id/flag_apply_btn" />
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/folder_app_pair.xml b/res/layout/folder_app_pair.xml
new file mode 100644
index 0000000..acecd46
--- /dev/null
+++ b/res/layout/folder_app_pair.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<com.android.launcher3.apppairs.AppPairIcon
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:focusable="true"
+    launcher:iconDisplay="folder" >
+    <com.android.launcher3.apppairs.AppPairIconGraphic
+        android:id="@+id/app_pair_icon_graphic"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:focusable="false" />
+    <com.android.launcher3.BubbleTextView
+        style="@style/BaseIcon"
+        android:id="@+id/app_pair_icon_name"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:focusable="false"
+        android:layout_gravity="top"
+        android:textColor="?attr/folderTextColor"
+        launcher:iconDisplay="folder" />
+</com.android.launcher3.apppairs.AppPairIcon>
\ No newline at end of file
diff --git a/res/layout/folder_icon.xml b/res/layout/folder_icon.xml
index 4093744..6af346e 100644
--- a/res/layout/folder_icon.xml
+++ b/res/layout/folder_icon.xml
@@ -19,7 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
-    android:focusable="true" >
+    android:focusable="true"
+    android:defaultFocusHighlightEnabled="false">
     <com.android.launcher3.views.DoubleShadowBubbleTextView
         style="@style/BaseIcon.Workspace"
         android:id="@+id/folder_icon_name"
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 82b0b8d..d14dcd5 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,4 +21,6 @@
     android:layout_height="match_parent"
     android:theme="@style/HomeScreenElementTheme"
     android:importantForAccessibility="no"
+    android:clickable="false"
+    android:longClickable="false"
     launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/layout/notification_content.xml b/res/layout/notification_content.xml
deleted file mode 100644
index 0763d48..0000000
--- a/res/layout/notification_content.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<com.android.launcher3.notification.NotificationMainView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_container_height"
-    android:orientation="vertical">
-
-    <!-- header -->
-    <FrameLayout
-        android:id="@+id/header"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingEnd="@dimen/notification_padding_end"
-        android:paddingTop="@dimen/notification_padding_header_top"
-        android:paddingStart="@dimen/notification_header_padding_start">
-        <TextView
-            android:id="@+id/notification_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="top|start"
-            android:text="@string/notifications_header"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="@dimen/notification_header_text_size"
-            style="@style/TextHeadline"/>
-        <TextView
-            android:id="@+id/notification_count"
-            android:layout_width="@dimen/notification_circle_icon_size"
-            android:layout_height="@dimen/notification_circle_icon_size"
-            android:background="@drawable/notification_circle"
-            android:layout_gravity="top|end"
-            android:gravity="center"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="@dimen/notification_header_count_text_size"
-            style="@style/TextHeadline"/>
-    </FrameLayout>
-
-    <!-- Main view -->
-    <FrameLayout
-        android:id="@+id/main_view"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="@dimen/notification_padding_top"
-        android:paddingBottom="@dimen/notification_padding_bottom"
-        android:focusable="true" >
-
-        <LinearLayout
-            android:id="@+id/text_and_background"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:orientation="vertical"
-            android:paddingEnd="@dimen/notification_padding_end"
-            android:paddingStart="@dimen/notification_main_text_padding_start">
-            <TextView
-                android:id="@+id/title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:lines="1"
-                android:textAlignment="viewStart"
-                android:textColor="?android:attr/textColorPrimary"
-                android:textSize="@dimen/notification_main_title_size"
-                style="@style/TextHeadline" />
-
-            <TextView
-                android:id="@+id/text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:lines="1"
-                android:textColor="?android:attr/textColorPrimary"
-                android:textSize="@dimen/notification_main_text_size" />
-        </LinearLayout>
-
-        <View
-            android:id="@+id/popup_item_icon"
-            android:layout_width="@dimen/notification_icon_size"
-            android:layout_height="@dimen/notification_icon_size"
-            android:layout_gravity="start|center_vertical"
-            android:layout_marginStart="@dimen/notification_icon_padding_start"/>
-
-    </FrameLayout>
-</com.android.launcher3.notification.NotificationMainView>
\ No newline at end of file
diff --git a/res/drawable/icon_menu_background.xml b/res/layout/predicted_app_icon.xml
similarity index 65%
copy from res/drawable/icon_menu_background.xml
copy to res/layout/predicted_app_icon.xml
index 8a95c3e..52df694 100644
--- a/res/drawable/icon_menu_background.xml
+++ b/res/layout/predicted_app_icon.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2023 The Android Open Source Project
+<!-- Copyright (C) 2008 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.
@@ -14,8 +13,5 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
-    android:shape="rectangle">
-    <solid android:color="?androidprv:attr/materialColorSurfaceBright" />
-</shape>
\ No newline at end of file
+
+<com.android.launcher3.views.DoubleShadowBubbleTextView style="@style/BaseIcon.Workspace" />
diff --git a/res/layout/private_space_divider.xml b/res/layout/private_space_divider.xml
new file mode 100644
index 0000000..fff8629
--- /dev/null
+++ b/res/layout/private_space_divider.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/private_space_divider"
+    android:importantForAccessibility="no"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingLeft="@dimen/ps_app_divider_padding"
+    android:paddingRight="@dimen/ps_app_divider_padding"
+    android:src="@drawable/private_space_app_divider"
+    android:scaleType="fitXY"
+    android:focusable="false" />
\ No newline at end of file
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 24e290d..84554e4 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -18,34 +18,61 @@
 <RelativeLayout
         android:id="@+id/ps_header_layout"
         xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
         android:layout_width="match_parent"
         android:layout_height="@dimen/ps_header_height"
         android:background="@drawable/bg_ps_header"
         android:clipToOutline="true"
         android:gravity="center_vertical"
+        android:textDirection="locale"
         android:orientation="horizontal">
 
-    <ImageButton
-        android:id="@+id/ps_lock_unlock_button"
+    <LinearLayout
+        android:id="@+id/settingsAndLockGroup"
         android:layout_width="wrap_content"
-        android:layout_height="@dimen/ps_header_image_height"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:gravity="center_vertical"
         android:layout_alignParentEnd="true"
-        android:layout_centerVertical="true"
-        android:background="@android:color/transparent"
-        android:layout_marginEnd="@dimen/ps_header_layout_margin"
-        android:contentDescription="@string/ps_container_lock_unlock_button" />
-
-    <ImageButton
-        android:id="@+id/ps_settings_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/ps_header_image_height"
-        android:layout_toStartOf="@+id/ps_lock_unlock_button"
-        android:layout_centerVertical="true"
-        android:background="@android:color/transparent"
-        android:layout_marginEnd="@dimen/ps_header_settings_icon_margin_end"
-        android:src="@drawable/bg_ps_settings_button"
-        android:contentDescription="@string/ps_container_settings" />
-
+        android:animateLayoutChanges="false">
+        <ImageButton
+            android:id="@+id/ps_settings_button"
+            android:layout_width="@dimen/ps_header_image_height"
+            android:layout_height="@dimen/ps_header_image_height"
+            android:background="@drawable/ps_settings_background"
+            android:src="@drawable/ic_ps_settings"
+            android:contentDescription="@string/ps_container_settings" />
+        <LinearLayout
+            android:id="@+id/ps_lock_unlock_button"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/ps_header_image_height"
+            android:background="@drawable/ps_lock_background"
+            android:gravity="center_vertical"
+            android:layout_marginEnd="@dimen/ps_lock_button_margin_end"
+            android:contentDescription="@string/ps_container_lock_unlock_button">
+            <ImageView
+                android:id="@+id/lock_icon"
+                android:layout_width="@dimen/ps_lock_icon_size"
+                android:layout_height="@dimen/ps_lock_icon_size"
+                android:layout_marginTop="@dimen/ps_lock_icon_margin_top"
+                android:layout_marginBottom="@dimen/ps_lock_icon_margin_bottom"
+                android:importantForAccessibility="no"
+                android:src="@drawable/ic_lock"
+                app:tint="@color/material_color_primary_fixed_dim"
+                android:scaleType="center"/>
+            <TextView
+                android:id="@+id/lock_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/ps_lock_icon_text_margin_start_expanded"
+                android:layout_marginEnd="@dimen/ps_lock_icon_text_margin_end_expanded"
+                android:textColor="@color/material_color_on_primary_fixed"
+                android:textSize="14sp"
+                android:text="@string/ps_container_lock_title"
+                android:visibility="gone"
+                style="@style/TextHeadline"/>
+        </LinearLayout>
+    </LinearLayout>
     <ImageView
         android:id="@+id/ps_transition_image"
         android:layout_width="wrap_content"
@@ -60,9 +87,11 @@
     <TextView
         android:id="@+id/ps_container_header"
         android:layout_width="wrap_content"
-        android:layout_height="@dimen/ps_header_text_height"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/ps_header_text_height"
         android:layout_alignParentStart="true"
         android:layout_centerVertical="true"
+        android:layout_toStartOf="@+id/settingsAndLockGroup"
         android:gravity="center_vertical"
         android:layout_marginStart="@dimen/ps_header_layout_margin"
         android:text="@string/ps_container_title"
diff --git a/res/layout/snackbar.xml b/res/layout/snackbar.xml
index b818943..6bc1729 100644
--- a/res/layout/snackbar.xml
+++ b/res/layout/snackbar.xml
@@ -39,6 +39,7 @@
         android:paddingLeft="8dp"
         android:paddingRight="8dp"
         android:background="?android:attr/selectableItemBackground"
+        android:longClickable="false"
         android:textStyle="bold"
         android:textSize="@dimen/snackbar_max_text_size"
         android:textColor="?android:attr/colorAccent"
diff --git a/res/layout/switch_preference_with_settings.xml b/res/layout/switch_preference_with_settings.xml
deleted file mode 100644
index cd51833..0000000
--- a/res/layout/switch_preference_with_settings.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:gravity="center_vertical">
-
-    <ImageView
-        android:id="@+id/settings"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:src="@drawable/ic_setting"
-        android:forceDarkAllowed="true"
-        android:padding="12dp"
-        android:background="?android:attr/selectableItemBackgroundBorderless" />
-
-    <View
-        android:id="@+id/divider"
-        android:layout_width="1dp"
-        android:layout_height="30dp"
-        android:layout_marginEnd="8dp"
-        android:background="?android:attr/listDivider" />
-
-    <!-- Note: seems we need focusable="false" and clickable="false" when moving to androidx -->
-    <Switch
-        android:id="@android:id/switch_widget"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:background="@null" />
-</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml
index 31f4870..43a8aac 100644
--- a/res/layout/user_folder_icon_normalized.xml
+++ b/res/layout/user_folder_icon_normalized.xml
@@ -18,6 +18,7 @@
     xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:defaultFocusHighlightEnabled="false"
     android:orientation="vertical" >
 
     <com.android.launcher3.folder.FolderPagedView
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 55dd1de..4533873 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -17,7 +17,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="0dp"
     android:layout_height="wrap_content"
-    android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
+    android:layout_marginStart="@dimen/widget_cell_horizontal_padding"
+    android:layout_marginEnd="@dimen/widget_cell_horizontal_padding"
     android:paddingVertical="@dimen/widget_cell_vertical_padding"
     android:layout_weight="1"
     android:orientation="vertical"
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 6db4fb5..12453a5 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -35,49 +35,71 @@
             android:layout_height="match_parent"
             android:importantForAccessibility="no"
             android:layout_gravity="fill"/>
-
-        <ImageView
-            android:id="@+id/widget_badge"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:importantForAccessibility="no"
-            android:layout_gravity="end|bottom"
-            android:layout_margin="@dimen/profile_badge_margin"/>
     </com.android.launcher3.widget.WidgetCellPreview>
 
-    <!-- The name of the widget. -->
-    <TextView
-        android:id="@+id/widget_name"
+    <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:ellipsize="end"
-        android:fadingEdge="horizontal"
-        android:gravity="center_horizontal"
-        android:singleLine="true"
-        android:maxLines="1"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textSize="@dimen/widget_cell_font_size" />
+        android:layout_height="wrap_content">
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:id="@+id/widget_text_container"
+            android:orientation="vertical">
+            <!-- The name of the widget. -->
+            <TextView
+                android:id="@+id/widget_name"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:fadingEdge="horizontal"
+                android:layout_gravity="center_horizontal"
+                android:gravity="center_horizontal|center_vertical"
+                android:singleLine="true"
+                android:maxLines="1"
+                android:textColor="?android:attr/textColorPrimary"
+                android:drawablePadding="@dimen/widget_cell_app_icon_padding"
+                android:textSize="@dimen/widget_cell_font_size" />
 
-    <!-- The original dimensions of the widget -->
-    <TextView
-        android:id="@+id/widget_dims"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textColor="?android:attr/textColorSecondary"
-        android:textSize="@dimen/widget_cell_font_size"
-        android:alpha="0.7" />
+                <!-- The original dimensions of the widget -->
+                <TextView
+                    android:id="@+id/widget_dims"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_horizontal"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:textSize="@dimen/widget_cell_font_size"
+                    android:alpha="0.7" />
 
-    <TextView
-        android:id="@+id/widget_description"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textSize="@dimen/widget_cell_font_size"
-        android:textColor="?android:attr/textColorSecondary"
-        android:maxLines="2"
-        android:ellipsize="end"
-        android:fadingEdge="horizontal"
-        android:alpha="0.7" />
+                <TextView
+                    android:id="@+id/widget_description"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_horizontal"
+                    android:textSize="@dimen/widget_cell_font_size"
+                    android:textColor="?android:attr/textColorSecondary"
+                    android:maxLines="2"
+                    android:ellipsize="end"
+                    android:fadingEdge="horizontal"
+                    android:alpha="0.7" />
+        </LinearLayout>
 
-</merge>
\ No newline at end of file
+        <Button
+            android:id="@+id/widget_add_button"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/widget_cell_add_button_height"
+            android:layout_gravity="center"
+            android:minWidth="0dp"
+            android:paddingStart="@dimen/widget_cell_add_button_start_padding"
+            android:paddingEnd="@dimen/widget_cell_add_button_end_padding"
+            android:text="@string/widget_add_button_label"
+            android:textColor="?attr/widgetPickerAddButtonTextColor"
+            android:textSize="@dimen/widget_cell_font_size"
+            android:gravity="center"
+            android:visibility="gone"
+            android:drawableStart="@drawable/ic_plus"
+            android:drawablePadding="8dp"
+            android:drawableTint="?attr/widgetPickerAddButtonTextColor"
+            android:background="@drawable/widget_cell_add_button_background" />
+    </FrameLayout>
+</merge>
diff --git a/res/layout/widget_recommendations.xml b/res/layout/widget_recommendations.xml
new file mode 100644
index 0000000..5879b0f
--- /dev/null
+++ b/res/layout/widget_recommendations.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto">
+
+    <!--
+    Shown when there are more than one pages
+    Note: on page change, using accessibility live region lets user know that the title has changed.
+    -->
+    <TextView
+        android:id="@+id/recommendations_page_title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="12dp"
+        android:layout_marginTop="16dp"
+        android:accessibilityLiveRegion="polite"
+        android:gravity="center_horizontal"
+        android:layout_gravity="top"
+        android:lineHeight="20sp"
+        android:textColor="?attr/widgetPickerTitleColor"
+        android:textFontWeight="500"
+        android:textSize="16sp"
+        android:maxLines="1"
+        android:paddingHorizontal="8dp"
+        android:ellipsize="end"
+        android:visibility="gone" />
+    <!-- Shown when there are more than one pages -->
+    <com.android.launcher3.pageindicators.PageIndicatorDots
+        android:id="@+id/widget_recommendations_page_indicator"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|top"
+        android:elevation="1dp"
+        android:visibility="gone" />
+    <!--
+     Note: importantForAccessibility = yes on this view ensures that with talkback, when user
+     swipes right on the last item in current page, they are taken to the next page. And, doing
+     the same on the last page, takes them to the next section e.g. apps list in single pane
+     picker.
+    -->
+    <com.android.launcher3.widget.picker.WidgetRecommendationsView
+        android:id="@+id/widget_recommendations_view"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_gravity="center"
+        android:layout_weight="1"
+        android:background="@drawable/widgets_surface_background"
+        android:importantForAccessibility="yes"
+        launcher:pageIndicator="@+id/widget_recommendations_page_indicator" />
+</merge>
\ No newline at end of file
diff --git a/res/layout/widget_recommendations_table.xml b/res/layout/widget_recommendations_table.xml
new file mode 100644
index 0000000..b53d2d5
--- /dev/null
+++ b/res/layout/widget_recommendations_table.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingVertical="@dimen/widget_recommendations_table_vertical_padding" />
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 47bf9e7..009359c 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -45,7 +45,7 @@
             android:visibility="gone"
             android:textSize="18sp"
             android:layout_below="@id/search_and_recommendations_container"
-            tools:text="No widgets available" />
+            tools:text="@string/no_widgets_available" />
 
         <!-- Fast scroller popup -->
         <TextView
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 069d4bc..8dc785a 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -73,15 +73,19 @@
             <include layout="@layout/widgets_search_bar" />
         </FrameLayout>
 
-        <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
-            android:id="@+id/recommended_widget_table"
+        <!-- Shown when there are recommendations to display -->
+        <LinearLayout
+            android:id="@+id/widget_recommendations_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
-            android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+            android:layout_marginBottom="8dp"
             android:background="@drawable/widgets_surface_background"
-            android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
-            android:visibility="gone" />
+            android:orientation="vertical"
+            android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+            android:visibility="gone">
+            <include layout="@layout/widget_recommendations" />
+        </LinearLayout>
 
         <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
             android:id="@+id/tabs"
@@ -89,7 +93,7 @@
             android:layout_height="64dp"
             android:gravity="center_horizontal"
             android:orientation="horizontal"
-            android:paddingVertical="8dp"
+            android:paddingBottom="8dp"
             android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
             android:background="?attr/widgetPickerPrimarySurfaceColor"
             style="@style/TextHeadline"
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index 25bbad4..5427732 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -29,7 +29,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/collapse_handle"
-        android:paddingBottom="16dp"
+        android:paddingBottom="8dp"
         android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
         android:clipToOutline="true"
         android:orientation="vertical">
@@ -56,14 +56,18 @@
             <include layout="@layout/widgets_search_bar" />
         </FrameLayout>
 
-        <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
-            android:id="@+id/recommended_widget_table"
+        <!-- Shown when there are recommendations to display -->
+        <LinearLayout
+            android:id="@+id/widget_recommendations_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
+            android:layout_marginBottom="8dp"
             android:background="@drawable/widgets_surface_background"
-            android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
-            android:visibility="gone" />
+            android:orientation="vertical"
+            android:visibility="gone">
+            <include layout="@layout/widget_recommendations" />
+        </LinearLayout>
     </com.android.launcher3.views.StickyHeaderLayout>
 
 </merge>
\ No newline at end of file
diff --git a/res/layout/widgets_list_row_header_two_pane.xml b/res/layout/widgets_list_row_header_two_pane.xml
index c0a6ea8..bdb2aed 100644
--- a/res/layout/widgets_list_row_header_two_pane.xml
+++ b/res/layout/widgets_list_row_header_two_pane.xml
@@ -23,6 +23,7 @@
     android:importantForAccessibility="yes"
     android:focusable="true"
     launcher:appIconSize="48dp"
+    launcher:collapsable="false"
     android:descendantFocusability="afterDescendants"
     android:background="@drawable/bg_widgets_header_two_pane" >
 
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index 01c1b10..bb2b7bd 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -47,6 +47,16 @@
             android:textColor="?attr/widgetPickerTitleColor"
             android:textSize="24sp" />
 
+        <TextView
+            android:id="@+id/no_widgets_text"
+            style="@style/PrimaryHeadline"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center"
+            android:textSize="18sp"
+            android:visibility="gone"
+            tools:text="@string/no_widgets_available" />
+
         <LinearLayout
             android:id="@+id/linear_layout_container"
             android:layout_width="match_parent"
@@ -57,6 +67,9 @@
                 android:id="@+id/recycler_view_container"
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:paddingBottom="24dp"
                 android:layout_gravity="start"
                 android:layout_weight="0.33">
                 <TextView
@@ -81,47 +94,49 @@
             </FrameLayout>
 
             <FrameLayout
-                android:id="@+id/right_pane_container"
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
-                android:layout_weight="0.67"
-                android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
-                android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
-                android:gravity="end"
-                android:layout_gravity="end"
-                android:orientation="horizontal">
-                <TextView
-                    android:id="@+id/no_widgets_text"
-                    style="@style/PrimaryHeadline"
+                android:layout_weight="0.67">
+                <FrameLayout
+                    android:id="@+id/right_pane_container"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:gravity="center"
-                    android:textSize="18sp"
-                    android:visibility="gone"
-                    tools:text="No widgets available" />
-                <ScrollView
-                    android:id="@+id/right_pane_scroll_view"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:fillViewport="true">
-                    <LinearLayout
-                        android:orientation="vertical"
+                    android:layout_marginVertical="@dimen/widget_picker_vertical_margin_right_pane"
+                    android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+                    android:gravity="end"
+                    android:layout_gravity="end"
+                    android:orientation="horizontal">
+                    <ScrollView
+                        android:id="@+id/right_pane_scroll_view"
                         android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_vertical"
-                        android:clipToOutline="true"
-                        android:paddingBottom="36dp"
+                        android:layout_height="match_parent"
                         android:background="@drawable/widgets_surface_background"
-                        android:id="@+id/right_pane">
-                        <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
-                            android:id="@+id/recommended_widget_table"
+                        android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+                        android:clipToOutline="true"
+                        android:fillViewport="true">
+                        <LinearLayout
+                            android:orientation="vertical"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content"
-                            android:paddingHorizontal=
-                                "@dimen/widget_list_horizontal_margin_two_pane"
-                            android:visibility="gone" />
-                    </LinearLayout>
-                </ScrollView>
+                            android:gravity="center_vertical"
+                            android:clipToOutline="true"
+                            android:paddingBottom="36dp"
+                            android:background="@drawable/widgets_surface_background"
+                            android:importantForAccessibility="yes"
+                            android:id="@+id/right_pane">
+                            <!-- Shown when there are recommendations to display -->
+                            <LinearLayout
+                                android:id="@+id/widget_recommendations_container"
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent"
+                                android:background="@drawable/widgets_surface_background"
+                                android:orientation="vertical"
+                                android:visibility="gone">
+                                <include layout="@layout/widget_recommendations" />
+                            </LinearLayout>
+                        </LinearLayout>
+                    </ScrollView>
+                </FrameLayout>
             </FrameLayout>
         </LinearLayout>
     </com.android.launcher3.views.SpringRelativeLayout>
diff --git a/res/layout/widgets_two_pane_sheet_paged_view.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
index 442957a..887efb8 100644
--- a/res/layout/widgets_two_pane_sheet_paged_view.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -22,6 +22,8 @@
         android:gravity="start"
         android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
         android:layout_gravity="start"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_alignParentStart="true">
         <com.android.launcher3.widget.picker.WidgetPagedView
             android:id="@+id/widgets_view_pager"
@@ -66,7 +68,7 @@
                 <include layout="@layout/widgets_search_bar" />
             </FrameLayout>
 
-            <LinearLayout
+            <FrameLayout
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:id="@+id/suggestions_header"
@@ -74,7 +76,7 @@
                 android:orientation="horizontal"
                 android:background="?attr/widgetPickerPrimarySurfaceColor"
                 launcher:layout_sticky="true">
-            </LinearLayout>
+            </FrameLayout>
 
             <com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
                 android:id="@+id/tabs"
diff --git a/res/layout/widgets_two_pane_sheet_recyclerview.xml b/res/layout/widgets_two_pane_sheet_recyclerview.xml
index c9c855c..f3d3b16 100644
--- a/res/layout/widgets_two_pane_sheet_recyclerview.xml
+++ b/res/layout/widgets_two_pane_sheet_recyclerview.xml
@@ -21,6 +21,7 @@
         android:layout_height="match_parent"
         android:gravity="start"
         android:layout_gravity="start"
+        android:clipChildren="false"
         android:layout_alignParentStart="true">
 
         <com.android.launcher3.widget.picker.WidgetsRecyclerView
@@ -45,24 +46,22 @@
                 android:background="?attr/widgetPickerPrimarySurfaceColor"
                 android:clipToPadding="false"
                 android:elevation="0.1dp"
-                android:paddingBottom="8dp"
+                android:paddingBottom="16dp"
                 android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
                 launcher:layout_sticky="true">
 
                 <include layout="@layout/widgets_search_bar" />
             </FrameLayout>
 
-            <LinearLayout
+            <FrameLayout
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:id="@+id/suggestions_header"
-                android:layout_marginTop="8dp"
                 android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
                 android:paddingBottom="16dp"
-                android:orientation="horizontal"
                 android:background="?attr/widgetPickerPrimarySurfaceColor"
                 launcher:layout_sticky="true">
-            </LinearLayout>
+            </FrameLayout>
         </com.android.launcher3.views.StickyHeaderLayout>
     </FrameLayout>
 </merge>
\ No newline at end of file
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index eeb7f4f..f557fb6 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -19,7 +19,7 @@
     android:paddingTop="@dimen/work_edu_card_margin"
     android:paddingBottom="@dimen/work_edu_card_bottom_margin"
     android:gravity="center">
-    <RelativeLayout
+    <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
@@ -28,40 +28,33 @@
         android:paddingEnd="@dimen/work_card_margin"
         android:paddingStart="@dimen/work_card_margin"
         android:paddingTop="@dimen/work_card_margin"
+        android:paddingBottom="@dimen/work_card_margin"
         android:id="@+id/wrapper">
         <TextView
             style="@style/PrimaryHeadline"
             android:textColor="?android:attr/textColorPrimary"
             android:id="@+id/work_apps_paused_title"
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="@dimen/work_card_margin"
-            android:layout_marginEnd="@dimen/work_card_margin"
+            android:layout_weight="1"
+            android:paddingEnd="@dimen/work_edu_card_text_end_margin"
             android:text="@string/work_profile_edu_work_apps"
             android:textDirection="locale"
             android:textSize="18sp" />
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/padded_rounded_button_height"
-            android:orientation="horizontal">
-            <FrameLayout
-                android:layout_width="@dimen/rounded_button_width"
-                android:layout_height="@dimen/rounded_button_width"
-                android:layout_alignParentEnd="true"
-                android:background="@drawable/rounded_action_button"
-                android:padding="@dimen/rounded_button_padding">
-                <ImageButton
-                    android:id="@+id/action_btn"
-                    android:layout_width="@dimen/x_icon_size"
-                    android:layout_height="@dimen/x_icon_size"
-                    android:layout_gravity="center"
-                    android:padding="@dimen/x_icon_padding"
-                    android:contentDescription="@string/accessibility_close"
-                    android:src="@drawable/ic_remove_no_shadow" />
-            </FrameLayout>
-        </RelativeLayout>
-    </RelativeLayout>
-
-
-
-</com.android.launcher3.allapps.WorkEduCard>
\ No newline at end of file
+        <FrameLayout
+            android:layout_width="@dimen/rounded_button_width"
+            android:layout_height="@dimen/rounded_button_width"
+            android:background="@drawable/rounded_action_button"
+            android:padding="@dimen/rounded_button_padding">
+            <ImageButton
+                android:id="@+id/action_btn"
+                android:layout_width="@dimen/x_icon_size"
+                android:layout_height="@dimen/x_icon_size"
+                android:layout_gravity="center"
+                android:contentDescription="@string/accessibility_close"
+                android:padding="@dimen/x_icon_padding"
+                android:background="@android:color/transparent"
+                android:src="@drawable/ic_remove_no_shadow" />
+        </FrameLayout>
+    </LinearLayout>
+</com.android.launcher3.allapps.WorkEduCard>
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 276d73e..b3484c9 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -24,12 +24,15 @@
     android:background="@drawable/work_mode_fab_background"
     android:forceHasOverlappingRendering="false"
     android:contentDescription="@string/work_apps_pause_btn_text"
+    android:paddingStart="@dimen/work_mode_fab_background_start_padding"
+    android:paddingEnd="@dimen/work_mode_fab_background_end_padding"
     android:animateLayoutChanges="true">
     <ImageView
         android:id="@+id/work_icon"
         android:layout_width="@dimen/work_fab_icon_size"
         android:layout_height="@dimen/work_fab_icon_size"
         android:importantForAccessibility="no"
+        android:layout_marginEnd="@dimen/work_fab_icon_end_margin"
         android:src="@drawable/ic_corp_off"
         android:tint="@color/work_fab_icon_color"
         android:scaleType="center"/>
@@ -43,7 +46,7 @@
         android:includeFontPadding="false"
         android:textDirection="locale"
         android:text="@string/work_apps_pause_btn_text"
-        android:layout_marginStart="@dimen/work_fab_text_start_margin"
+        android:layout_marginEnd="@dimen/work_fab_text_end_margin"
         android:ellipsize="end"
         android:maxLines="1"
         style="@style/TextHeadline"/>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index ea6e0fa..7c6aa83 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Stoor apppaar"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hierdie apppaar word nie op hierdie toestel gesteun nie"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vou die toestel oop om hierdie apppaar te gebruik"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Apppaar is nie beskikbaar nie"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Raak en hou om \'n legstuk te skuif."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en hou om \'n legstuk te skuif of gebruik gepasmaakte handelinge."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed by %2$d hoog"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk, %2$d wyd en %3$d hoog"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Raak en hou die legstuk om dit op die tuisskerm rond te beweeg"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Voeg by tuisskerm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by tuisskerm gevoeg"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Voorstelle"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Noodsaaklikhede"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nuus en tydskrifte"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jou ontspansone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Vermaak"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosiaal"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Gesondheid en fiksheid"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weer"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Voorgestel vir jou"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-legstukke aan die regterkant, soektog en opsies aan die linkerkant"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# legstuk}other{# legstukke}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kortpad}other{# kortpaaie}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Werk"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Gesprekke"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Neem notas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Voeg by"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Voeg <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Nuttige inligting binne jou bereik"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Jy kan legstukke by jou tuisskerm voeg om inligting te kry sonder om programme oop te maak"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om legstukinstellings te verander"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lys werkprogramme"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwyder"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Programinligting"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Appinligting"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installeer privaat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
@@ -115,8 +131,8 @@
     <string name="title_change_settings" msgid="1376365968844349552">"Verander instellings"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Wys kennisgewingkolle"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Ontwikkelaaropsies"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Voeg programikone by tuisskerm"</string>
-    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Vir nuwe programme"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Voeg appikone by tuisskerm"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Vir nuwe apps"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwyder"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Soek"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeer tans; <xliff:g id="PROGRESS">%2$s</xliff:g> voltooi"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laai tans af, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wag tans om te installeer"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is geargiveer. Tik om af te laai."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Programopdatering word vereis"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Die program vir hierdie ikoon is nie opgedateer nie. Jy kan dit handmatig opdateer om hierdie kortpad weer te aktiveer, of die ikoon verwyder."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Dateer op"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Verminder hoogte"</string>
     <string name="widget_resized" msgid="9130327887929620">"Legstukgrootte is verander na breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Kortpaaie"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Kortpaaie en kennisgewings"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Maak toe"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Maak toe"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Kennisgewing is toegemaak"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persoonlik"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privaat ruimte"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om op te stel of oop te maak"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privaat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Sluit"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privaat Ruimte-oorgang"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installeer apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installeer apps in privaat ruimte"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oorvloei"</string>
 </resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 893f4c4..fe5b51a 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"የመተግበሪያ ጥምረትን ያስቀምጡ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ይህ የመተግበሪያ ጥምረት በዚህ መሣሪያ ላይ አይደገፍም"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ይህን የመተግበሪያ ጥምረት ለመጠቀም መሣሪያን ይዘርጉ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"የመተግበሪያ ጥምረት አይገኝም"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ምግብርን ለማንቀሳቀስ ይንኩ እና ይያዙ።"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ምግብርን ለማንቀሳቀስ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ ያድርጉ እና ይያዙ።"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ስፋት በ%2$d ከፍታ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"የ<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ምግብር"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"የ<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ምግብር፣ %2$d ስፋት በ%3$d ቁመት"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"በመነሻ ማያ ገፅ አካባቢ ላይ ለማንቀሳቀስ ነክተው ይያዙት"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ወደ መነሻ ማያ ገፅ አክል"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ምግብር ወደ መነሻ ማያ ገፅ ታክሏል"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"የአስተያየት ጥቆማዎች"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ጠቃሚ ነገሮች"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ዜና እና መጽሔቶች"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"የሚያርፉበት ቦታዎ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"መዝናኛ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ማህበራዊ"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ጤና እና የአካል ብቃት"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"የአየር ሁኔታ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ለእርስዎ የተጠቆሙ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ምግብሮች በቀኝ በኩል፣ ፍለጋ እና አማራጮች በግራ በኩል"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ምግብር}one{# ምግብሮች}other{# ምግብሮች}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# አቋራጭ}one{# አቋራጭ}other{# አቋራጮች}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>፣ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ሥራ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ውይይቶች"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"የማስታወሻ አያያዝ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"አክል"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"ምግብር <xliff:g id="WIDGET_NAME">%1$s</xliff:g>ን አክል"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"በጣቶችዎ ጫፎች ላይ ጠቃሚ መረጃ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"መተግበሪያዎችን ሳይከፍቱ መረጃ ለማግኘት በመነሻ ማያ ገጽዎ ላይ ምግብሮችን ማከል ይችላሉ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"የምግብር ቅንብሮችን ለመለወጥ መታ ያድርጉ"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"አስወግድ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"አራግፍ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"የመተግበሪያ መረጃ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"በግል ይጫኑ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> በመጫን ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቅቋል"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> በመውረድ ላይ፣ <xliff:g id="PROGRESS">%2$s</xliff:g> ተጠናቋል"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ለመጫን በመጠበቅ ላይ"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> በማህደር ተቀምጧል። ለማውረድ መታ ያድርጉ።"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"መተግበሪያ ማዘመን አስፈላጊ ነው"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"የዚህ አዶ መተግበሪያ አልተዘመነም። ይህን አቋራጭ ዳግም ለማንቃት በራስዎ ማዘመን ወይም አዶውን ማስወገድ ይችላሉ።"</string>
     <string name="dialog_update" msgid="2178028071796141234">"አዘምን"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ቁመት ይቀንሱ"</string>
     <string name="widget_resized" msgid="9130327887929620">"የመግብር መጠን ወደ ስፋት <xliff:g id="NUMBER_0">%1$s</xliff:g> ቁመት <xliff:g id="NUMBER_1">%2$s</xliff:g> ተለውጧል"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"አቋራጮች"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"አቋራጮች እና ማሳወቂያዎች"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"አሰናብት"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ዝጋ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ማሳወቂያ ተሰናብቷል"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"የግል"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ሥራ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"የሥራ መገለጫ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"አጣራ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"አልተሳካም፦ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"የግል ቦታ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ለማዋቀር ወይም ለመክፈት መታ ያድርጉ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"የግል"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ቆልፍ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"የግል ቦታ ሽግግር"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"መተግበሪያዎችን ይጫኑ"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"መተግበሪያዎችን ወደ የግል ቦታ ይጫኑ"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ትርፍ ፍሰት"</string>
 </resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index a2a43db..7db41c3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"الشاشة الرئيسية"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"تقسيم الشاشة"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‏معلومات تطبيق %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"حفظ إعدادات ميزة \"استخدام تطبيقين في الوقت نفسه\""</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"حفظ استخدام التطبيقين معًا"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | ‏<xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"لا يمكن استخدام هذين التطبيقَين في الوقت نفسه على هذا الجهاز"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"افتح الجهاز لاستخدام هذين التطبيقَين في الوقت نفسه"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ميزة \"استخدام تطبيقين في الوقت نفسه\" غير متوفّرة"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏العرض %1$d الطول %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"أداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية."</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏التطبيق المصغّرة \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\"، بعرض ‎%2$d وارتفاع ‎%3$d"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"إضافة إلى الشاشة الرئيسية"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"تمت إضافة الأداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g> إلى الشاشة الرئيسية."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"اقتراحات"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"الأساسيات"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"الأخبار والمجلات"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"محتوى ترفيهي مقترَح"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"الترفيه"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"التواصل الاجتماعي"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"الصحة واللياقة البدنية"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"الطقس"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"اقتراحاتنا لك"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"تطبيقات \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" المصغّرة على اليسار، والبحث والخيارات على اليمين"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"تطبيقات العمل"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"المحادثات"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"تدوين الملاحظات"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"إضافة"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"إضافة التطبيق المصغّر \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
     <string name="widget_education_header" msgid="4874760613775913787">"معلومات مفيدة في متناول يديك"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"للحصول على معلومات بدون فتح التطبيقات، يمكنك إضافة التطبيقات المصغّرة إلى الشاشة الرئيسية."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"انقر لتغيير إعدادات الأداة"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"إزالة"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"إلغاء التثبيت"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"معلومات عن التطبيق"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"تثبيت في مساحة خاصّة"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"جارٍ تثبيت <xliff:g id="NAME">%1$s</xliff:g>، مستوى التقدم: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"جارٍ تنزيل <xliff:g id="NAME">%1$s</xliff:g>، اكتمل <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> في انتظار التثبيت"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"تمت أرشفة تطبيق <xliff:g id="NAME">%1$s</xliff:g>. انقر للتنزيل."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"مطلوب تحديث التطبيق"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"لم يتمّ تحديث التطبيق الخاص بهذا الرمز. يمكنك تحديث التطبيق يدويًا لإعادة تفعيل هذا الاختصار أو إزالة الرمز."</string>
     <string name="dialog_update" msgid="2178028071796141234">"تحديث"</string>
@@ -154,13 +171,11 @@
     <string name="action_decrease_height" msgid="282377193880900022">"تقليل الارتفاع"</string>
     <string name="widget_resized" msgid="9130327887929620">"تم تغيير حجم الأداة إلى العرض <xliff:g id="NUMBER_0">%1$s</xliff:g> والارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"الاختصارات"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"الاختصارات والإشعارات"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"تجاهل"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"إغلاق"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"تم تجاهل الإشعار"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصية"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"للعمل"</string>
-    <string name="work_profile_toggle_label" msgid="3081029915775481146">"الملف الشخصي للعمل"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"ملف العمل"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"تحمل تطبيقات العمل مميّزة بشارة ومرئية لمشرف تكنولوجيا المعلومات."</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"حسنًا"</string>
     <string name="work_apps_paused_title" msgid="3040901117349444598">"تطبيقات العمل متوقفة مؤقتًا"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فلتر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
     <string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"النقر للإعداد أو الفتح"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"قفل"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"النقل إلى المساحة الخاصة"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"تثبيت التطبيقات"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"تثبيت التطبيقات في المساحة الخاصّة"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"القائمة الكاملة"</string>
 </resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 93c5e3a..7872e45 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"এপৰ পেয়াৰ ছেভ কৰক"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইচটোত এই এপ্‌ পেয়াৰ কৰাৰ সুবিধাটো সমৰ্থিত নহয়"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"এই এপ্‌ পেয়াৰ কৰাৰ সুবিধাটো ব্যৱহাৰ কৰিবলৈ ডিভাইচটো আনফ’ল্ড কৰক"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"এপ্‌ পেয়াৰ কৰাৰ সুবিধাটো উপলব্ধ নহয়"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ৱিজেট স্থানান্তৰ কৰিবলৈ টিপি ধৰি ৰাখক।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"কোনো ৱিজেট স্থানান্তৰ কৰিবলৈ দুবাৰ টিপি ধৰি ৰাখক অথবা কাষ্টম কাৰ্য ব্যৱহাৰ কৰক।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d বহল x %2$d ওখ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট, %2$d বহল %3$d ওখ"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ৱিজেটটো গৃহ স্ক্ৰীনৰ আশে-পাশে নিবলৈ সেইটোত স্পৰ্শ কৰি ধৰি ৰাখক"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"গৃহ স্ক্ৰীনত যোগ কৰক"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেটটো গৃহ স্ক্ৰীনত যোগ দিয়া হৈছে"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"পৰামৰ্শ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"অত্যাৱশ্যকীয়সমূহ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"বাতৰি আৰু আলোচনী"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"আপোনাৰ পচন্দৰ স্থান"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"মনোৰঞ্জন"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"সামাজিক"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"স্বাস্থ্য আৰু সুস্থতা"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"বতৰ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"আপোনাৰ বাবে পৰামৰ্শ হিচাপে আগবঢ়োৱা"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ৱিজেট সোঁফালে, সন্ধান আৰু বিকল্পসমূহ বাওঁফালে"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# টা ৱিজেট}one{# টা ৱিজেট}other{# টা ৱিজেট}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# টা শ্বৰ্টকাট}one{# টা শ্বৰ্টকাট}other{# টা শ্বৰ্টকাট}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"কৰ্মস্থান"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"বাৰ্তালাপ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"টোকা গ্ৰহণ কৰা"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"যোগ দিয়ক"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট যোগ দিয়ক"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"আপোনাৰ আঙুলিৰে টিপতে উপযোগী তথ্য পাওক"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"এপ্ নোখোলাকৈ তথ্য পাবলৈ আপুনি নিজৰ গৃহ স্ক্ৰীনত ৱিজেট যোগ দিব পাৰে"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ৱিজেটৰ ছেটিং সলনি কৰিবলৈ টিপক"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"আঁতৰাওক"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনষ্টল কৰক"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"এপ্‌ সম্পৰ্কীয় তথ্য"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"গোপনে ইনষ্টল কৰক"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্‌টো পিন কৰক"</string>
@@ -108,7 +124,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"গৃহ স্ক্ৰীন ঘূৰোৱাৰ অনুমতি দিয়ক"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ফ\'নটো যেতিয়া ঘূৰোৱা হয়"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"জাননী বিন্দু"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"অন আছে"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"অন কৰা আছে"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"অফ আছে"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"জাননীৰ এক্সেছৰ প্ৰয়োজন"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"জাননী সম্পৰ্কীয় বিন্দুবোৰ দেখুৱাবলৈ <xliff:g id="NAME">%1$s</xliff:g>ৰ বাবে এপৰ জাননীসমূহ অন কৰক"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হৈছে"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনল’ড কৰি থকা হৈছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূৰ্ণ হ’ল"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনষ্টল হোৱালৈ অপেক্ষা কৰি থকা হৈছে"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> আৰ্কাইভ কৰা হৈছে। ডাউনল’ড কৰিবলৈ টিপক।"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"এপ্‌টো আপডে’ট কৰা প্ৰয়োজন"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"এই চিহ্নটোৰ এপ্‌টো আপডে’ট কৰা হোৱা নাই। আপুনি এই শ্বৰ্টকাটটো পুনৰ সক্ষম কৰিবলৈ মেনুৱেলী আপডে’ট কৰিব পাৰে অথবা চিহ্নটো আঁতৰাব পাৰে।"</string>
     <string name="dialog_update" msgid="2178028071796141234">"আপডে’ট কৰক"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা হ্ৰাস কৰক"</string>
     <string name="widget_resized" msgid="9130327887929620">"ৱিজেটৰ আকাৰ সলনি কৰি প্ৰস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> আৰু উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> কৰা হ’ল"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"শ্বৰ্টকাটসমূহ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"শ্বৰ্টকাট আৰু জাননীসমূহ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"অগ্ৰাহ্য কৰক"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"বন্ধ কৰক"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"জাননী অগ্ৰাহ্য কৰা হৈছে"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ব্যক্তিগত"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"কৰ্মস্থান"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"কৰ্মস্থানৰ প্ৰ\'ফাইল"</string>
@@ -173,10 +188,14 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"আনপজ কৰক"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টাৰ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"বিফল: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পে’চ"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"প্ৰাইভেট স্পে\'চ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ছেট আপ কৰিবলৈ টিপক অথবা খোলক"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পে’চ লক/আনলক কৰক"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"প্ৰাইভেট স্পে\'চ লক/আনলক কৰক"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"লক কৰক"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পে’চৰ স্থানান্তৰণ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"এপ্‌ ইনষ্টল কৰক"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"এপ্‌সমূহ প্ৰাইভেট স্পেচত ইনষ্টল কৰক"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"অ’ভাৰফ্ল’"</string>
 </resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 31d485d..0f67a22 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Tətbiq cütünü saxlayın"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu tətbiq cütü bu cihazda dəstəklənmir"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bu tətbiq cütündən istifadə üçün cihazı açın"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Tətbiq cütü əlçatan deyil"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidceti daşımaq üçün toxunub saxlayın."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidceti daşımaq üçün iki dəfə toxunub saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d hündürlük %1$d enində"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti, eni - %2$d, hündürlüyü - %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Əsas ekranda hərəkət etdirmək üçün vidcetə toxunub saxlayın"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Əsas ekrana əlavə edin"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti əsas ekrana əlavə edildi"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Təkliflər"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Əsaslar"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Xəbər və jurnallar"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"İstirahət zonası"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Əyləncə"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosial"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sağlamlıq və fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Hava"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Təklif edirik"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidcetləri sağda, axtarış və seçimlər solda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidcet}other{# vidcet}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# qısayol}other{# qısayol}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"İş"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Söhbətlər"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Qeydgötürmə"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Əlavə edin"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidcet əlavə edin"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Faydalı məlumatlar barmaqlarınızın ucunda"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Tətbiqləri açmadan məlumat almaq üçün Əsas ekrana vidcet əlavə edə bilərsiniz"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidcet ayarlarını dəyişmək üçün toxunun"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Silin"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sistemdən sil"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Tətbiq haqqında"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Məxfi quraşdırın"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> quraşdırır, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlanıb"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> endirilir, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> yüklənmək üçün gözləyir"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> arxivləndi. Endirmək üçün toxunun."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Tətbiqin güncəllənməsi tələb edilir"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Bu ikona üçün tətbiq güncəllənməyib. Bu qısayolu yenidən aktivləşdirmək üçün manual olaraq güncəlləyə və ya ikonanı silə bilərsiniz."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Güncəlləyin"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Hündürlüyü azaldın"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidcetin eni <xliff:g id="NUMBER_0">%1$s</xliff:g> hündürlüyü <xliff:g id="NUMBER_1">%2$s</xliff:g> kimi ölçüləndirildi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Qısa yollar"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Qısayol və bildirişlər"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Rədd edin"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Bağlayın"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Bildiriş rədd edildi"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Şəxsi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toxunaraq ayarlayın və ya açın"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Şəxsi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Kilidləyin"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Şəxsi məkana keçid"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Tətbiqlər quraşdırın"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Tətbiqləri şəxsi sahədə quraşdırın"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kənara çıxma"</string>
 </resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index aa08cc4..59c4700 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ovaj par aplikacija nije podržan na ovom uređaju"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Otvorite uređaj da biste koristili ovaj par aplikacija"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite radi pomeranja vidžeta."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da biste pomerali vidžet ili koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidžet"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidžet, širina %2$d i visina %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da biste ga pomerali po početnom ekranu"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Neophodne aplikacije"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novosti i časopisi"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Društvene mreže"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdravlje i fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Vreme"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Predloženo za vas"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Vidžeti <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> sa desne strane, pretraga i opcije sa leve strane"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzacije"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pravljenje beležaka"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajte vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Da biste pronašli informacije bez otvaranja aplikacija, možete da dodate vidžete na početni ekran"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Infor. o aplikaciji"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj na privatni"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalira, <xliff:g id="PROGRESS">%2$s</xliff:g> gotovo"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> je arhivirana. Dodirnite da biste je preuzeli."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Treba da ažurirate aplikaciju"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete da je ručno ažurirate da biste ponovo omogućili ovu prečicu ili uklonite ikonu."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> i visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obaveštenja"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zatvori"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Obaveštenje je odbačeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lično"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Poslovni profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste podesili ili otvorili"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prenos privatnog prostora"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliraj aplikacije u privatan prostor"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopno"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index ae47fa0..6946ed5 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Захаваць спалучэнне праграм"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Дадзенае спалучэнне праграм не падтрымліваецца на гэтай прыладзе"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Каб выкарыстоўваць гэта спалучэнне праграм, раскладзіце прыладу"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Спалучэнне праграм недаступнае"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Націсніце і ўтрымлівайце віджэт для перамяшчэння."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Дакраніцеся двойчы і ўтрымлівайце, каб перамясціць віджэт або выкарыстоўваць спецыяльныя дзеянні."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Шырына: %1$d, вышыня: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\": шырыня – %2$d, вышыня – %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Утрымліваючы віджэт націснутым, перамяшчайце яго па галоўным экране"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Дадаць на галоўны экран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" дададзены на галоўны экран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Прапановы"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Асноўнае"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Навіны і часопісы"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона адпачынку"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забавы"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Сацыяльныя сеткі"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здароўе і фітнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Надвор\'е"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Рэкамендавана для вас"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Віджэты праграмы \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" справа, пошук і параметры злева"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджэт}one{# віджэт}few{# віджэты}many{# віджэтаў}other{# віджэта}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыкі}many{# ярлыкоў}other{# ярлыка}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Працоўныя"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Размовы"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Стварэнне нататак"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Дадаць"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Дадаць віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Карысная інфармацыя ў вас пад рукой"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Каб не адкрываць праграмы для прагляду патрэбнай інфармацыі, дадайце віджэты на галоўны экран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Націсніце, каб змяніць налады віджэта"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Выдаліць"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Дэінсталяваць"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі аб праграме"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Усталяваць прыватна"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
@@ -108,7 +124,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Дазволіць паварот галоўнага экрана"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Значкі апавяшчэнняў"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укл."</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Уключана"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Выкл."</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Усталёўваецца праграма \"<xliff:g id="NAME">%1$s</xliff:g>\", завершана <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Ідзе спампоўка <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завершана"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чакае ўсталёўкі"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Праграма \"<xliff:g id="NAME">%1$s</xliff:g>\" знаходзіцца ў архіве. Націсніце, каб спампаваць."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Неабходна абнавіць праграму"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Гэта версія праграмы састарэла. Абнавіце праграму ўручную, каб зноў карыстацца гэтым ярлыком, або выдаліце значок."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Абнавіць"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Паменшыць вышыню"</string>
     <string name="widget_resized" msgid="9130327887929620">"Памеры віджэта зменены на: шырыня <xliff:g id="NUMBER_0">%1$s</xliff:g>, вышыня <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыкі"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлыкі і апавяшчэнні"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Адхіліць"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Закрыць"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Апавяшчэнне адхілена"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Асабістыя"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Працоўныя"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Працоўны профіль"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Прыватная вобласць"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Націсніце, каб наладзіць або адкрыць"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Прыватная"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Заблакіраваць"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Пераход у прыватную вобласць"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Усталяваць праграмы"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Усталяваць праграмы ў прыватнай прасторы"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дадатковае меню"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2f196ca..0b92509 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Запазване на двойката приложения"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Тази двойка приложения не се поддържа на устройството"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Отворете устройството, за да използвате тази двойка приложения"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Двойката приложения не е налице"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Докоснете и задръжте за преместване на приспособление"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Докоснете двукратно и задръжте за преместване на приспособление или използвайте персонал. действия."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d и височина %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> приспособление"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Приспособлението „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ е широко %2$d и високо %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Докоснете приспособлението и го задръжте, за да го местите на началния екран"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Добавяне към началния екран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Приспособлението <xliff:g id="WIDGET_NAME">%1$s</xliff:g> е добавено към началния екран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предложения"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Приспособления, които трябва да изпробвате"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новини и списания"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зоната ви за разпускане"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Социални мрежи"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здраве и фитнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Времето"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Предложено за вас"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Приспособленията за <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> са отдясно, търсенето и опциите – отляво"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# приспособление}other{# приспособления}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пряк път}other{# преки пътя}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Служебни"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Разговори"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Водене на бележки"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Добавяне"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавяне на приспособлението „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Лесен достъп до полезна информация"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"За да получавате информация, без да отваряте приложенията, можете да добавите приспособления към началния екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Докоснете, за да промените настройките на приспособлението"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Премахване"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталиране"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Информация за прилож."</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. в частно простр."</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завършено"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се изтегля. Завършено: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> изчаква инсталиране"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Приложението <xliff:g id="NAME">%1$s</xliff:g> е архивирано. Докоснете за изтегляне."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Изисква се актуализация на приложението"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Приложението за тази икона не е актуализирано. Можете да го актуализирате ръчно, за да активирате отново този пряк път, или да премахнете иконата."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Актуализиране"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намаляване на височината"</string>
     <string name="widget_resized" msgid="9130327887929620">"Приспособлението е преоразмерено към ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> и височина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Преки пътища"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Преки пътища и известия"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Отхвърляне"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Затваряне"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Известието е отхвърлено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лични"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Служебни"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Служебен потребителски профил"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтър"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Лично пространство"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Докоснете за настройване или отваряне"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Заключване"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Преминаване към личното пространство"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталиране на приложения"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталиране на приложения в частно пространство"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Препълване"</string>
 </resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 8c08794..54238cf 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"অ্যাপ পেয়ার সেভ করুন"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইসে এই অ্যাপ পেয়ারটি কাজ করে না"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"এই অ্যাপ পেয়ার ব্যবহার করতে ডিভাইস আনফোল্ড করুন"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"অ্যাপ পেয়ার উপলভ্য নেই"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"কোনও উইজেট সরাতে সেটি টাচ করে ধরে রাখুন।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"একটি উইজেট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d উচ্চতা অনুযায়ী %1$d প্রস্থ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>টি উইজেট"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট, %2$d প্রস্থ ও %3$d উচ্চতা"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"হোম স্ক্রিনের যেকোনও জায়গায় নিয়ে যেতে, উইজেট টাচ করে ধরে থাকুন"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"হোম স্ক্রিনে যোগ করুন"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট হোম স্ক্রিনে যোগ করা হয়েছে"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"সাজেশন"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"প্রয়োজনীয় জিনিস"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"খবর ও ম্যাগাজিন"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"আপনার চিল জোন"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"বিনোদন"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"সোশ্যাল"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"স্বাস্থ্য ও ফিটনেস"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"আবহাওয়া"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"আপনার জন্য সাজেস্ট করা হয়েছে"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> উইজেট ডানদিকে, সার্চ ও বিকল্প বাঁদিকে রয়েছে"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#টি উইজেট}one{#টি উইজেট}other{#টি উইজেট}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#টি শর্টকাট}one{#টি শর্টকাট}other{#টি শর্টকাট}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"অফিস"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"কথোপকথন"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"নোট নেওয়া"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"যোগ করুন"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট যোগ করুন"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"সহজেই দরকারি তথ্য পান"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"অ্যাপ না খুলেই তথ্য পাওয়ার জন্য, হোম স্ক্রিনে উইজেট যোগ করতে পারবেন"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"উইজেট সেটিংস পরিবর্তন করতে ট্যাপ করুন"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"সরান"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ব্যক্তিগত প্রোফাইলে ইনস্টল করুন"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
@@ -108,7 +124,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"হোম স্ক্রিন রোটেট করার অনুমতি দিন"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"যখন ফোনটি ঘোরানো হয়"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"বিজ্ঞপ্তি ডট"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"চালু"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"চালু করা আছে"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"বন্ধ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"বিজ্ঞপ্তিতে অ্যাক্সেস প্রয়োজন"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"বিজ্ঞপ্তির ডটগুলি দেখানোর জন্য, <xliff:g id="NAME">%1$s</xliff:g> এর অ্যাপ বিজ্ঞপ্তি চালু করুন"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টল করা হচ্ছে, <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পূর্ণ হয়েছে"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ডাউনলোড হচ্ছে <xliff:g id="PROGRESS">%2$s</xliff:g> সম্পন্ন হয়েছে"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ইনস্টলের অপেক্ষায় রয়েছে"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> আর্কাইভ করা হয়েছে। ডাউনলোড করতে ট্যাপ করুন।"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"অ্যাপটি আপডেট করা প্রয়োজন"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"এই আইকনের জন্য অ্যাপটি আপডেট করা নেই। এই শর্টকার্ট আবার চালু করতে, আপনি ম্যানুয়ালি আপডেট করতে বা সরিয়ে দিতে পারবেন।"</string>
     <string name="dialog_update" msgid="2178028071796141234">"আপডেট করুন"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"উচ্চতা কমান"</string>
     <string name="widget_resized" msgid="9130327887929620">"উইজেটের আকার প্রস্থ <xliff:g id="NUMBER_0">%1$s</xliff:g> উচ্চতা <xliff:g id="NUMBER_1">%2$s</xliff:g> তে পরিবর্তন করা হয়েছে"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"শর্টকাট"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"শর্টকাট এবং বিজ্ঞপ্তি"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"খারিজ করুন"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"বন্ধ করুন"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"বিজ্ঞপ্তি খারিজ করা হয়েছে"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ব্যক্তিগত"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"অফিস"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"অফিসের প্রোফাইল"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টার"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পেস"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"সেট-আপ করতে বা খুলতে ট্যাপ করুন"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"লক"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পেস ট্রানজিট করা"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"অ্যাপ ইনস্টল করুন"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"প্রাইভেট স্পেসে অ্যাপ ইনস্টল করুন"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ওভারফ্লো"</string>
 </resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 9641416..d0d4ce6 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Par aplikacija nije podržan na uređaju"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Otklopite uređaj da koristite ovaj par aplikacija"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da pomjerite vidžet."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da pomjerite vidžet ili da koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i držite vidžet da ga pomjerate po početnom ekranu"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, širina %2$d, visina %3$d"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da ga pomjerate po početnom ekranu"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> je dodan na početni ekran"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovne aplikacije"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Vijesti i časopisi"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša zona opuštanja"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Društvene mreže"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdravlje i fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Vrijeme"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Predloženo za vas"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Vidžeti aplikacije <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> su na desnoj, a pretraživanje i opcije na lijevoj strani"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Razgovori"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilješki"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodavanje vidžeta <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Da dobijete informacije bez otvaranja aplikacija, možete dodati vidžete na početni ekran"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da promijenite postavke vidžeta"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u priv. pr."</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka da se instalira"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Arhivirana je aplikacija <xliff:g id="NAME">%1$s</xliff:g>. Dodirnite je da je preuzmete."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Potrebno je ažurirati aplikaciju"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete je ažurirati ručno da ponovo omogućite ovu prečicu ili možete ukloniti ikonu."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promijenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obavještenja"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zatvaranje"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Obavještenje je odbačeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lično"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovno"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Radni profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da postavite ili otvorite"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključaj"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instaliranje aplikacija"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopni meni"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 25a8ce6..b57de6b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Desa la parella d\'aplicacions"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aquesta parella d\'aplicacions no s\'admet en aquest dispositiu"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desplega el dispositiu per utilitzar aquesta parella d\'aplicacions"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La parella d\'aplicacions no està disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Fes doble toc i mantén premut per moure un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Fes doble toc i mantén premut per moure un widget o per utilitzar accions personalitzades."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d d\'amplada per %2$d d\'alçada"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d d\'amplada per %3$d d\'alçària"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premut el widget per moure\'l per la pantalla d\'inici"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Afegeix a la pantalla d\'inici"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"El widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> s\'ha afegit a la pantalla d\'inici"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggeriments"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essencials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Notícies i revistes"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"La teva zona de relax"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entreteniment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salut i fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Temps"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments per a tu"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la dreta, cerca i opcions a l\'esquerra"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Treball"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Converses"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Presa de notes"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Afegeix"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Afegeix el widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informació útil a l\'abast de la mà"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Per obtenir informació sense obrir les aplicacions, pots afegir widgets a la pantalla d\'inici"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca per canviar la configuració del widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Suprimeix"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstal·la"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informació de l\'aplicació"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal·la en privat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
@@ -103,7 +119,7 @@
     <string name="app_pair_name_format" msgid="8134106404716224054">"Parella d\'aplicacions: <xliff:g id="APP1">%1$s</xliff:g> i <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Estil i fons de pantalla"</string>
     <string name="edit_home_screen" msgid="8947858375782098427">"Edita la pantalla d\'inici"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Config. pantalla d\'inici"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Configuració de la pantalla d\'inici"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desactivada per l\'administrador"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Permet la rotació de la pantalla d\'inici"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"En girar el telèfon"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"S\'està instal·lant <xliff:g id="NAME">%1$s</xliff:g>; s\'ha completat un <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"S\'està baixant <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completat"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"S\'està esperant per instal·lar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"L\'aplicació <xliff:g id="NAME">%1$s</xliff:g> està arxivada. Toca per baixar."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Cal actualitzar l\'aplicació"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"L\'aplicació d\'aquesta icona no està actualitzada. Pots actualitzar-la manualment per tornar a activar aquesta drecera o pots suprimir la icona."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Actualitza"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Redueix l\'alçada"</string>
     <string name="widget_resized" msgid="9130327887929620">"S\'ha canviat la mida del widget a l\'amplada <xliff:g id="NUMBER_0">%1$s</xliff:g> i l\'alçada <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Dreceres"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Dreceres i notificacions"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignora"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Tanca"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"S\'ha ignorat la notificació"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Treball"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de treball"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espai privat"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca per configurar o obrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueja"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Canvia a Espai privat"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instal·la apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal·la les aplicacions a Espai privat"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú addicional"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 4927508..e9fef0c 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Domů"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělit obrazovku"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Uložit pár aplikací"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Uložit dvojici aplikací"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikací není na tomto zařízení podporován"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Pokud chcete použít tento pár aplikací, rozložte zařízení"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Dvojice aplikací není k dispozici"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget přesunete klepnutím a podržením."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"šířka %1$d, výška %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, šířka %2$d, výška %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pokud chcete widgetem pohybovat po ploše, podržte ho"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sociální sítě"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdraví a fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Počasí"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Návrhy pro vás"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgety <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vpravo, vyhledávání a možnosti vlevo"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ # widget}few{# widgety}many{# widgetu}other{# widgetů}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# zkratka}few{# zkratky}many{# zkratky}other{# zkratek}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Práce"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzace"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Psaní poznámek"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Přidat"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Přidat widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Užitečné informace na dosah"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Pokud chcete mít informace k dispozici bez otevírání aplikací, můžete si na plochu přidat widgety"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím změníte nastavení widgetu"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstranit"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstalovat"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikaci"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalovat soukromě"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g>, dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Stahování aplikace <xliff:g id="NAME">%1$s</xliff:g> (dokončeno <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalace aplikace <xliff:g id="NAME">%1$s</xliff:g> čeká na zahájení"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikace <xliff:g id="NAME">%1$s</xliff:g> je archivována. Klepnutím ji stáhnete."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Je nutná aktualizace aplikace"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikace pro tuto ikonu není nainstalována. Můžete ji ručně aktualizovat, aby zkratka znovu fungovala, případně můžete ikonu odstranit."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Aktualizovat"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Snížit výšku"</string>
     <string name="widget_resized" msgid="9130327887929620">"Velikost widgetu upravena: šířka <xliff:g id="NUMBER_0">%1$s</xliff:g>, výška <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Zkratky"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Zkratky a oznámení"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Zavřít"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zavřít"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Oznámení bylo zavřeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobní"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovní"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovní profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Soukromý prostor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavíte nebo otevřete"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Soukromé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zamknout"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Převádění soukromého prostoru"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalovat aplikace"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalovat aplikace do soukromého prostoru"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozbalovací nabídka"</string>
 </resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 9d5a55f..6502e63 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Gem appsammenknytning"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne appsammenknytning understøttes ikke på enheden"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Fold enheden ud for at bruge denne appsammenknytning"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Appsammenknytning er ikke tilgængelig"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Hold en widget nede for at flytte den."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryk to gange, og hold en widget nede for at flytte den eller bruge tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget, %2$d i bredden og %3$d i højden"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Hold widgetten nede for at flytte den rundt på startskærmen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Føj til startskærm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g> blev føjet til startskærmen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Vigtige ting"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Aviser og blade"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Dit afslapningshjørne"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underholdning"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Socialt"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sundhed og fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Vejr"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Forslag til dig"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-widgets til højre, søgning og valgmuligheder til venstre"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genvej}one{# genvej}other{# genveje}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbejde"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Samtaler"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Tilføj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tilføj <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-widget"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Nyttige oplysninger lige ved hånden"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Hvis du vil have oplysninger uden at åbne apps, kan du føje widgets til din startskærm"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryk for at ændre widgetindstillinger"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Appinfo"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer (privat)"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeres. <xliff:g id="PROGRESS">%2$s</xliff:g> fuldført"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloades. <xliff:g id="PROGRESS">%2$s</xliff:g> er gennemført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> venter på at installere"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> er arkiveret Tryk for at downloade."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Appen skal opdateres"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Appen, der tilhører dette ikon, er ikke opdateret. Du kan opdatere appen manuelt for at genaktivere denne genvej, eller du kan fjerne ikonet."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Opdater"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducer højden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Størrelsen for widgetten er ændret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og højde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Genveje"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Genveje og notifikationer"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Afvis"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Luk"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notifikationen blev afvist"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personlige"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Arbejde"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbejdsprofil"</string>
@@ -173,10 +188,14 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Genoptag"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tryk for at konfigurere eller åbne"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private rum"</string>
-    <string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private rum"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
+    <string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private område"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apps i privat område"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overløb"</string>
 </resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 04d9682..80941c7 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"App-Paar speichern"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Gerät aufklappen, um dieses App-Paar zu verwenden"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-Paar nicht verfügbar"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets berühren und halten"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breit und %2$d hoch"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“, %2$d breit und %3$d hoch"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Wenn du das Widget auf dem Startbildschirm verschieben möchtest, halte es gedrückt"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Zum Startbildschirm hinzufügen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-Widget zum Startbildschirm hinzugefügt"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Vorschläge"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Must-haves"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nachrichten und Zeitschriften"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zum Entspannen"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Unterhaltung"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Soziale Netzwerke"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Gesundheit und Fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Wetter"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Vorschläge für dich"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-Widgets rechts, Suche und Optionen links"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# Widget}other{# Widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# Verknüpfung}other{# Verknüpfungen}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Geschäftlich"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Unterhaltungen"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notizen"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Hinzufügen"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ hinzufügen"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Praktische Informationen – immer zur Hand"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Wenn du Informationen erhalten möchtest, ohne Apps zu öffnen, kannst du deinem Startbildschirm Widgets hinzufügen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tippen, um die Widget-Einstellungen zu ändern"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Entfernen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App-Info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privat installieren"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
@@ -101,7 +117,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Ordner: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> Elemente"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Ordner: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> oder mehr Elemente"</string>
     <string name="app_pair_name_format" msgid="8134106404716224054">"App-Paar: <xliff:g id="APP1">%1$s</xliff:g> und <xliff:g id="APP2">%2$s</xliff:g>"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Hintergrund und Stil"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Hintergrund &amp; Stil"</string>
     <string name="edit_home_screen" msgid="8947858375782098427">"Startbildschirm bearbeiten"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Einstellungen"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Von deinem Administrator deaktiviert"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> wird installiert, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wird heruntergeladen, <xliff:g id="PROGRESS">%2$s</xliff:g> abgeschlossen"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Warten auf Installation von <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ist archiviert. Zum Herunterladen tippen."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App-Update erforderlich"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Die App für dieses Symbol wurde noch nicht aktualisiert. Du kannst sie manuell aktualisieren, um die Verknüpfung wieder zu aktivieren, oder das Symbol entfernen."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Aktualisieren"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Höhe verringern"</string>
     <string name="widget_resized" msgid="9130327887929620">"Größe des Widgets zu Breite <xliff:g id="NUMBER_0">%1$s</xliff:g> und Höhe <xliff:g id="NUMBER_1">%2$s</xliff:g> geändert"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Verknüpfungen"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Verknüpfungen und Benachrichtigungen"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Schließen"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Schließen"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Benachrichtigung geschlossen"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privat"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Geschäftlich"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Arbeitsprofil"</string>
@@ -173,10 +188,14 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nicht mehr pausieren"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Privater Bereich"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Privates Profil"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Zum Einrichten oder Öffnen tippen"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Sperren"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Sperrzustand des privaten Bereichs wird gerade geändert"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installieren"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps im privaten Bereich installieren"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Weitere Optionen"</string>
 </resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index bc8458b..a4f8692 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Αποθήκευση ζεύγους εφαρμογών"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Αυτό το ζεύγος εφαρμογών δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Ξεδιπλώστε τη συσκευή για να χρησιμοποιήσετε αυτό το ζεύγος εφαρμογών"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Το ζεύγος εφαρμογών δεν είναι διαθέσιμο"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Πατήστε παρατετ. για μετακίνηση γραφ. στοιχείου."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Πατήστε δύο φορές παρατεταμένα για μετακίνηση γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Πλάτος %1$d επί ύψος %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Γραφικό στοιχείο <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Γραφικό στοιχείο <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d πλάτος επί %3$d ύψος"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Αγγίξτε παρατεταμένα το γραφικό στοιχείο για να το μετακινήσετε στην αρχική οθόνη"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Προσθήκη στην αρχική οθόνη"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Το γραφικό στοιχείο <xliff:g id="WIDGET_NAME">%1$s</xliff:g> προστέθηκε στην αρχική οθόνη."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Προτάσεις"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Απαραίτητα"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Ειδήσεις και περιοδικά"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ο δικός σας τρόπος χαλάρωσης"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Ψυχαγωγία"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Κοινωνικά δίκτυα"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Υγεία και φυσική κατάσταση"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Καιρός"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Προτεινόμενα για εσάς"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Γραφικά στοιχεία <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> στα δεξιά, αναζήτηση και επιλογές στα αριστερά"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# γραφικό στοιχείο}other{# γραφικά στοιχεία}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# συντόμευση}other{# συντομεύσεις}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Εργασίας"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Συζητήσεις"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Δημιουργία σημειώσεων"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Προσθήκη"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Προσθήκη του γραφικού στοιχείου <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Χρήσιμες πληροφορίες στη διάθεσή σας"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Για να λάβετε πληροφορίες χωρίς να ανοίξετε εφαρμογές, μπορείτε να προσθέσετε γραφικά στοιχεία στην αρχική οθόνη."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Πατήστε για αλλαγή των ρυθμίσεων του γραφικού στοιχείου"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Κατάργηση"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Απεγκατάσταση"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Πληροφ. εφαρμογής"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Εγκατ. στο απόρρητο"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται η εφαρμογή"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Έχει ολοκληρωθεί το <xliff:g id="PROGRESS">%2$s</xliff:g> της εγκατάστασης της εφαρμογής <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Λήψη <xliff:g id="NAME">%1$s</xliff:g>, ολοκληρώθηκε <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> σε αναμονή για εγκατάσταση"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Η εφαρμογή <xliff:g id="NAME">%1$s</xliff:g> είναι αρχειοθετημένη. Πατήστε για λήψη."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Απαιτείται ενημέρωση της εφαρμογής"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Η εφαρμογή για αυτό το εικονίδιο δεν έχει ενημερωθεί. Μπορείτε να την ενημερώσετε μη αυτόματα για να ενεργοποιήσετε ξανά τη συγκεκριμένη συντόμευση ή να καταργήσετε το εικονίδιο."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ενημέρωση"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Μείωση του ύψους"</string>
     <string name="widget_resized" msgid="9130327887929620">"Έγινε προσαρμογή του μεγέθους του γραφικού στοιχείου σε <xliff:g id="NUMBER_0">%1$s</xliff:g> πλάτος και <xliff:g id="NUMBER_1">%2$s</xliff:g> ύψος"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Συντομεύσεις"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Συντομεύσεις και ειδοποιήσεις"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Παράβλεψη"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Κλείσιμο"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Η ειδοποίηση παραβλέφθηκε"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Προσωπικές"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Εργασίας"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Προφίλ εργασίας"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Φίλτρο"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Ιδιωτικός χώρος"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Πάτημα για ρύθμιση ή άνοιγμα"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Ιδιωτικό"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Κλείδωμα"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Μετάβαση στον Ιδιωτικό χώρο"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Εγκατάσταση εφαρμογών"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Εγκατάσταση εφαρμογών στον απόρρητο χώρο"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Υπερχείλιση"</string>
 </resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index c002ef9..8deac65 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget, %2$d wide by %3$d high"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News and magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health and fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is archived. Tap to download."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Close"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
 </resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 1ad42f3..ec69ea8 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap and hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget, %2$d wide by %3$d high"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News &amp; magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your Chill Zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health &amp; fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is archived. Tap to download."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget resized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Shortcuts"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Close"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to Private Space"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
 </resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index c002ef9..8deac65 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget, %2$d wide by %3$d high"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News and magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health and fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is archived. Tap to download."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Close"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
 </resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index c002ef9..8deac65 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Unfold device to use this app pair"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap &amp; hold to move a widget or use custom actions."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget, %2$d wide by %3$d high"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News and magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health and fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Work"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Note-taking"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Add"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Add <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Useful info at your fingertips"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"To get info without opening apps, you can add widgets to your home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tap to change widget settings"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remove"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installing, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> downloading, <xliff:g id="PROGRESS">%2$s</xliff:g> complete"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> waiting to install"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is archived. Tap to download."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App update required"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"The app for this icon isn\'t updated. You can update manually to re-enable this shortcut or remove the icon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Decrease height"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget re-sized to width <xliff:g id="NUMBER_0">%1$s</xliff:g> height <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Short cuts"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shortcuts and notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dismiss"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Close"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification dismissed"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Work profile"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Install apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
 </resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 81bb474..476ffda 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎App info for %1$s‎‏‎‎‏‎"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎Save app pair‎‏‎‎‏‎"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP1">%1$s</xliff:g>‎‏‎‎‏‏‏‎ | ‎‏‎‎‏‏‎<xliff:g id="APP2">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‎This app pair isn\'t supported on this device‎‏‎‎‏‎"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‏‏‎‏‎‎Unfold device to use this app pair‎‏‎‎‏‎"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎App pair isn\'t available‎‏‎‎‏‎"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‎Touch &amp; hold to move a widget.‎‏‎‎‏‎"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎Double-tap &amp; hold to move a widget or use custom actions.‎‏‎‎‏‎"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎%1$d × %2$d‎‏‎‎‏‎"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎%1$d wide by %2$d high‎‏‎‎‏‎"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget‎‏‎‎‏‎"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget, %2$d wide by %3$d high‎‏‎‎‏‎"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎Touch &amp; hold the widget to move it around the home screen‎‏‎‎‏‎"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎Add to home screen‎‏‎‎‏‎"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget added to home screen‎‏‎‎‏‎"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎Suggestions‎‏‎‎‏‎"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‎Essentials‎‏‎‎‏‎"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎News &amp; magazines‎‏‎‎‏‎"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎Your Chill Zone‎‏‎‎‏‎"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‏‎‎Entertainment‎‏‎‎‏‎"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‎‏‏‎‏‎Social‎‏‎‎‏‎"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‎‎‎Health &amp; fitness‎‏‎‎‏‎"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎Weather‎‏‎‎‏‎"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‏‎Suggested for you‎‏‎‎‏‎"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widgets on right, search and options on left‎‏‎‎‏‎"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎# widget‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎# widgets‎‏‎‎‏‎}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎# shortcut‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎# shortcuts‎‏‎‎‏‎}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎Work‎‏‎‎‏‎"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‎Conversations‎‏‎‎‏‎"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎Note-taking‎‏‎‎‏‎"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎Add‎‏‎‎‏‎"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎Add ‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget‎‏‎‎‏‎"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‎Useful info at your fingertips‎‏‎‎‏‎"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎To get info without opening apps, you can add widgets to your home screen‎‏‎‎‏‎"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‎Tap to change widget settings‎‏‎‎‏‎"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎Remove‎‏‎‎‏‎"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎Uninstall‎‏‎‎‏‎"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎App info‎‏‎‎‏‎"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‎‏‎Install in private‎‏‎‎‏‎"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎Install‎‏‎‎‏‎"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎Don\'t suggest app‎‏‎‎‏‎"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎Pin Prediction‎‏‎‎‏‎"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ installing, ‎‏‎‎‏‏‎<xliff:g id="PROGRESS">%2$s</xliff:g>‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ downloading, ‎‏‎‎‏‏‎<xliff:g id="PROGRESS">%2$s</xliff:g>‎‏‎‎‏‏‏‎ complete‎‏‎‎‏‎"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ waiting to install‎‏‎‎‏‎"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is archived. Tap to download.‎‏‎‎‏‎"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‎App update required‎‏‎‎‏‎"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎The app for this icon isn\'t updated. You can update manually to re-enable this shortcut, or remove the icon.‎‏‎‎‏‎"</string>
     <string name="dialog_update" msgid="2178028071796141234">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎Update‎‏‎‎‏‎"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎Decrease height‎‏‎‎‏‎"</string>
     <string name="widget_resized" msgid="9130327887929620">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‎‎‎Widget resized to width ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ height ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎Shortcuts‎‏‎‎‏‎"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎Shortcuts and notifications‎‏‎‎‏‎"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎Dismiss‎‏‎‎‏‎"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎Close‎‏‎‎‏‎"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎Notification dismissed‎‏‎‎‏‎"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎Personal‎‏‎‎‏‎"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‏‎‎Work‎‏‎‎‏‎"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎Work profile‎‏‎‎‏‎"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎Filter‎‏‎‎‏‎"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎Failed: ‎‏‎‎‏‏‎<xliff:g id="WHAT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="private_space_label" msgid="2359721649407947001">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎Private space‎‏‎‎‏‎"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎Tap to set up or open‎‏‎‎‏‎"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎Private‎‏‎‎‏‎"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎Private Space Settings‎‏‎‎‏‎"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎Lock/Unlock Private Space‎‏‎‎‏‎"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎Lock‎‏‎‎‏‎"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎Private Space Transitioning‎‏‎‎‏‎"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎Install apps‎‏‎‎‏‎"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‎Install apps to Private Space‎‏‎‎‏‎"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎Overflow‎‏‎‎‏‎"</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index d37b1e9..86b0de7 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación de apps"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"No se admite esta vinculación de apps en este dispositivo"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abre el dispositivo para usar esta vinculación de apps"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La vinculación de apps no está disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén presionado para mover un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Presiona dos veces y mantén presionado para mover un widget o usar acciones personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d de ancho por %3$d de alto"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén presionado el widget para moverlo por la pantalla principal"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Agregar a pantalla principal"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Se agregó el widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a la pantalla principal"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Imprescindibles"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y bienestar"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la derecha, búsqueda y opciones a la izquierda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabajo"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversaciones"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Agregar"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Agregar widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Información útil a tu alcance"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Para recibir información de apps sin abrirlas, puedes agregar widgets a la pantalla principal"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Presiona para cambiar la configuración del widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instala en privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -108,14 +124,14 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Permitir la rotación de la pantalla principal"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Al girar el teléfono"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Puntos de notificación"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activado"</string>
-    <string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivado"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activados"</string>
+    <string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivados"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Se necesita acceso a las notificaciones"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para mostrar los puntos de notificación, activa las notificaciones de la app para <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Cambiar la configuración"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Mostrar puntos de notificación"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Opciones para desarrolladores"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Agrega íconos de las apps a la pantalla principal"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Agregar íconos de las apps a la pantalla principal"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para nuevas apps"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Eliminar"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Se está instalando <xliff:g id="NAME">%1$s</xliff:g>; <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Se completó el <xliff:g id="PROGRESS">%2$s</xliff:g> de la descarga de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Instalación de <xliff:g id="NAME">%1$s</xliff:g> en espera"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> está archivada. Presiona para descargar."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Es necesario actualizar la app"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"No se actualizó la app de este ícono. Puedes actualizarla manualmente para rehabilitar el acceso directo, o bien quitar el ícono."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir la altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Se cambió la dimensión del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Accesos directos y notificaciones"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Descartar"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Se descartó la notificación"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personales"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"De trabajo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Presiona para configurar o abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloqueo"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pasar a Espacio privado"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instala apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instala las apps en el espacio privado"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ampliada"</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 7db8239..971bf81 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Guardar aplicaciones emparejadas"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Guardar apps emparejadas"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"El dispositivo no admite esta aplicación emparejada"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Despliega el dispositivo para usar esta aplicación emparejada"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La aplicación emparejada no está disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d de ancho por %3$d de alto"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén pulsado el widget para moverlo por la pantalla de inicio"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Añadir a pantalla de inicio"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> añadido a la pantalla de inicio"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Imprescindibles"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y actividad física"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"El tiempo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la derecha, búsqueda y opciones a la izquierda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabajo"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversaciones"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Añadir"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Añadir widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Información útil al alcance de la mano"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Para ver información sin abrir una aplicación, puedes añadir widgets a la pantalla de inicio"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar los ajustes del widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Información de la aplicación"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Descargar en privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -116,7 +132,7 @@
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Mostrar puntos de notificación"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Opciones para desarrolladores"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Añadir iconos de aplicaciones a la pantalla de inicio"</string>
-    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Añade el icono de una aplicación nueva instalada a la pantalla de inicio"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Para aplicaciones nuevas"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Desconocido"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Quitar"</string>
     <string name="abandoned_search" msgid="891119232568284442">"Buscar"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> está archivada. Toca para descargarla."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Debes actualizar la aplicación"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"La aplicación de este icono no está actualizada. Puedes actualizarla manualmente para volver a habilitar este acceso directo o puedes eliminar el icono."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Se ha modificado el tamaño del widget a <xliff:g id="NUMBER_0">%1$s</xliff:g> de ancho y <xliff:g id="NUMBER_1">%2$s</xliff:g> de alto"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Accesos directos y notificaciones"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Cerrar"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notificación ignorada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configurarlo o abrirlo"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Cambiar a espacio privado"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Descarg. apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Descargar aplicaciones en el espacio privado"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Desplegable"</string>
 </resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 9e4a534..46c530e 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Salvesta rakendusepaar"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"See rakendusepaar ei ole selles seadmes toetatud"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Selle rakendusepaari kasutamiseks voltige seade lahti"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Rakendusepaar ei ole saadaval"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidina teisaldamiseks puudutage ja hoidke all."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidina teisaldamiseks või kohandatud toimingute kasutamiseks topeltpuudutage ja hoidke all."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lai ja %2$d kõrge"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d lai ja %3$d kõrge"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Vidina teisaldamiseks avakuval puudutage vidinat pikalt"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lisa avakuvale"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati avakuvale"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Soovitused"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Põhiasjad"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uudised ja ajakirjad"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Teie lõõgastumiskoht"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Meelelahutus"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Suhtlus"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Tervis ja vormisolek"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ilm"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Teile soovitatud"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Teenuse <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidinad paremal, otsing ja valikud vasakul"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidin}other{# vidinat}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# otsetee}other{# otseteed}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Töö"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Vestlused"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Märkmete tegemine"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Lisa"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisa vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Kasulik teave on teie käeulatuses"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Teabe saamiseks rakendusi avamata võite oma avakuvale lisada vidinaid"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Puudutage vidina seadete muutmiseks"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Eemalda"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Rakenduse teave"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privaatselt installimine"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Üksust <xliff:g id="NAME">%1$s</xliff:g> installitakse, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Rakenduse <xliff:g id="NAME">%1$s</xliff:g> allalaadimine, <xliff:g id="PROGRESS">%2$s</xliff:g> on valmis"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> on installimise ootel"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> on arhiivitud. Puudutage allalaadimiseks."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Rakendust tuleb värskendada"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Selle ikooni rakendust pole värskendatud. Otsetee uuesti lubamiseks võite rakendust käsitsi värskendada või ikooni eemaldada."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Värskenda"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Vähenda kõrgust"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidina suurust muudeti. Laius: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Kõrgus: <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Otseteed"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Otseteed ja märguanded"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Loobu"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Sule"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Märguandest loobuti"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Isiklik"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Töö"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Tööprofiil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privaatne ruum"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Seadistamiseks või avamiseks puudutage"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privaatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lukk"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privaatse ruumi üleviimine"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Rakenduste installimine"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Rakenduste installimine privaatses ruumis"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ületäide"</string>
 </resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 4123096..acf67f2 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -26,20 +26,33 @@
     <string name="safemode_shortcut_error" msgid="9160126848219158407">"Deskargatutako aplikazioa modu seguruan desgaitu da"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgetak desgaitu egin dira modu seguruan"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"Lasterbideak ez daude erabilgarri"</string>
-    <string name="home_screen" msgid="5629429142036709174">"Hasierako pantaila"</string>
+    <string name="home_screen" msgid="5629429142036709174">"Orri nagusia"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantaila zatitzea"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Gorde aplikazio parea"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aplikazio pare hori ez da onartzen gailu honetan"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Zabaldu gailua aplikazio pare hau erabiltzeko"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Aplikazio parea ez dago erabilgarri"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Eduki sakatuta widget bat mugitzeko."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Sakatu birritan eta eduki sakatuta widget bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d zabal eta %2$d luze"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Widgeta hasierako pantailan zehar mugitzeko, eduki ezazu sakatuta"</string>
-    <string name="add_to_home_screen" msgid="9168649446635919791">"Gehitu hasierako pantailan"</string>
-    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta hasierako pantailan gehitu da"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta, %2$d zabal eta %3$d altu"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Widgeta orri nagusian zehar mugitzeko, eduki ezazu sakatuta"</string>
+    <string name="add_to_home_screen" msgid="9168649446635919791">"Gehitu orri nagusian"</string>
+    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta orri nagusian gehitu da"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iradokizunak"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Oinarrizkoak"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Albisteak eta aldizkariak"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Lasaitzeko gunea"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Aisia"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sare sozialak"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Osasuna eta ongizatea"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Eguraldia"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Zuri iradokiak"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> zerbitzuaren widgetak eskuinean, bilaketa eta aukerak ezkerrean"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lasterbide}other{# lasterbide}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,8 +65,10 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Lanekoak"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Elkarrizketak"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Oharrak idazteko"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Gehitu"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Gehitu <xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informazio erabilgarria beti eskura"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Aplikaziorik ireki beharrik gabe informazioa zuzenean jasotzeko, gehitu widgetak hasierako pantailan"</string>
+    <string name="widget_education_content" msgid="1731667670753497052">"Aplikaziorik ireki beharrik gabe informazioa zuzenean jasotzeko, gehitu widgetak orri nagusian"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Sakatu hau widgeten ezarpenak aldatzeko"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"Ados"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Aldatu widgeten ezarpenak"</string>
@@ -65,7 +80,7 @@
     <string name="notifications_header" msgid="1404149926117359025">"Jakinarazpenak"</string>
     <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Eduki sakatuta lasterbide bat mugitzeko."</string>
     <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Sakatu birritan eta eduki sakatuta lasterbide bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
-    <string name="out_of_space" msgid="6455557115204099579">"Ez dago tokirik hasierako pantailan"</string>
+    <string name="out_of_space" msgid="6455557115204099579">"Ez dago tokirik orri nagusian"</string>
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"Ez dago toki gehiago Gogokoak erretiluan"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"Aplikazioen zerrenda"</string>
     <string name="all_apps_search_results" msgid="5889367432531296759">"Bilaketa-emaitzak"</string>
@@ -74,15 +89,16 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Kendu"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalatu"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Aplikazioaren informazioa"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalatu pribatuan"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"Instalatu lasterbideak"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"Erabiltzaileak ezer egin gabe lasterbideak gehitzeko baimena ematen die aplikazioei."</string>
     <string name="permlab_read_settings" msgid="5136500343007704955">"irakurri hasierako pantailako ezarpenak eta lasterbideak"</string>
-    <string name="permdesc_read_settings" msgid="4208061150510996676">"Hasierako pantailako ezarpenak eta lasterbideak irakurtzeko baimena ematen die aplikazioei."</string>
+    <string name="permdesc_read_settings" msgid="4208061150510996676">"Hasierako pantailako ezarpenak eta lasterbideak irakurtzeko baimena ematen dio aplikazioari."</string>
     <string name="permlab_write_settings" msgid="4820028712156303762">"idatzi hasierako pantailako ezarpenak eta lasterbideak"</string>
-    <string name="permdesc_write_settings" msgid="726859348127868466">"Hasierako pantailako ezarpenak eta lasterbideak aldatzeko baimena ematen die aplikazioei."</string>
+    <string name="permdesc_write_settings" msgid="726859348127868466">"Hasierako pantailako ezarpenak eta lasterbideak aldatzeko baimena ematen dio aplikazioari."</string>
     <string name="gadget_error_text" msgid="740356548025791839">"Ezin da kargatu widgeta"</string>
     <string name="gadget_setup_text" msgid="8348374825537681407">"Widgetaren ezarpenak"</string>
     <string name="gadget_complete_setup_text" msgid="309040266978007925">"Sakatu konfiguratzen amaitzeko"</string>
@@ -91,8 +107,8 @@
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> desgaituta dago"</string>
     <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} aplikazioak # jakinarazpen dauka}other{{app_name} aplikazioak # jakinarazpen dauzka}}"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"%1$d/%2$d orria"</string>
-    <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d/%2$d hasierako pantaila"</string>
-    <string name="workspace_new_page" msgid="257366611030256142">"Hasierako pantailaren orri berria"</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>
     <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>
@@ -102,10 +118,10 @@
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"<xliff:g id="NAME">%1$s</xliff:g> karpeta (<xliff:g id="SIZE">%2$d</xliff:g> elementu edo gehiago)"</string>
     <string name="app_pair_name_format" msgid="8134106404716224054">"Aplikazio parea: <xliff:g id="APP1">%1$s</xliff:g> eta <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Horma-papera eta estiloa"</string>
-    <string name="edit_home_screen" msgid="8947858375782098427">"Editatu hasierako pantaila"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Hasierako pantailaren ezarpenak"</string>
+    <string name="edit_home_screen" msgid="8947858375782098427">"Editatu orri nagusia"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Orri nagusiko ezarpenak"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administratzaileak desgaitu du"</string>
-    <string name="allow_rotation_title" msgid="7222049633713050106">"Eman hasierako pantaila biratzeko baimena"</string>
+    <string name="allow_rotation_title" msgid="7222049633713050106">"Eman orri nagusia biratzeko baimena"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Telefonoa biratzean"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Jakinarazpen-biribiltxoak"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"Aktibatuta"</string>
@@ -115,7 +131,7 @@
     <string name="title_change_settings" msgid="1376365968844349552">"Aldatu ezarpenak"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Erakutsi jakinarazpen-biribiltxoak"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Garatzaileentzako aukerak"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Gehitu aplikazioen ikonoak hasierako pantailan"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Gehitu aplikazioen ikonoak orri nagusian"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Aplikazio berrien kasuan"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Ezezaguna"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Kendu"</string>
@@ -125,15 +141,16 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> instalatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> deskargatzen, <xliff:g id="PROGRESS">%2$s</xliff:g> osatuta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> instalatzeko zain"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> artxibatuta dago. Deskargatzeko, sakatu hau."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Aplikazioa eguneratu egin behar da"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Ikonoaren aplikazioa ez dago eguneratuta. Lasterbidea berriro gaitzeko, eskuz egunera dezakezu aplikazioa. Bestela, kendu ikonoa."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Eguneratu"</string>
     <string name="dialog_remove" msgid="6510806469849709407">"Kendu"</string>
     <string name="widgets_list" msgid="796804551140113767">"Widget-zerrenda"</string>
     <string name="widgets_list_closed" msgid="6141506579418771922">"Itxi da widget-zerrenda"</string>
-    <string name="action_add_to_workspace" msgid="215894119683164916">"Gehitu hasierako pantailan"</string>
+    <string name="action_add_to_workspace" msgid="215894119683164916">"Gehitu orri nagusian"</string>
     <string name="action_move_here" msgid="2170188780612570250">"Ekarri elementua hona"</string>
-    <string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua hasierako pantailan"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Gehitu da elementua orri nagusian"</string>
     <string name="item_removed" msgid="851119963877842327">"Kendu da elementua"</string>
     <string name="undo" msgid="4151576204245173321">"Desegin"</string>
     <string name="action_move" msgid="4339390619886385032">"Mugitu elementua"</string>
@@ -146,7 +163,7 @@
     <string name="added_to_folder" msgid="4793259502305558003">"Elementua karpetan gehitu da"</string>
     <string name="create_folder_with" msgid="4050141361160214248">"Sortu karpeta <xliff:g id="NAME">%1$s</xliff:g> elementuarekin"</string>
     <string name="folder_created" msgid="6409794597405184510">"Karpeta sortu da"</string>
-    <string name="action_move_to_workspace" msgid="39528912300293768">"Eraman hasierako pantailara"</string>
+    <string name="action_move_to_workspace" msgid="39528912300293768">"Eraman orri nagusira"</string>
     <string name="action_resize" msgid="1802976324781771067">"Aldatu tamaina"</string>
     <string name="action_increase_width" msgid="8773715375078513326">"Handitu zabalera"</string>
     <string name="action_increase_height" msgid="459390020612501122">"Handitu altuera"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Txikitu altuera"</string>
     <string name="widget_resized" msgid="9130327887929620">"Aldatu da widgetaren tamaina. Zabalera: <xliff:g id="NUMBER_0">%1$s</xliff:g>. Altuera: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Lasterbideak"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Lasterbideak eta jakinarazpenak"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Baztertu"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Itxi"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Baztertu egin da jakinarazpena"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pertsonalak"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Lanekoak"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Laneko profila"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Iragazi"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Eremu pribatua"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Sakatu konfiguratzeko edo irekitzeko"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Pribatua"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Blokeatu"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Eremu pribaturako trantsizioa"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalatu aplikazioak"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalatu aplikazioak eremu pribatuan"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Luzapena"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 161c7c5..163739a 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‏اطلاعات برنامه %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ذخیره جفت برنامه"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمی‌شود"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"برای استفاده از این جفت برنامه، دستگاه را باز کنید"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"جفت برنامه دردسترس نیست"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابه‌جا کردن ابزارک، لمس کنید و نگه دارید."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابه‌جا کردن ابزارک یا استفاده از کنش‌های سفارشی، دوضربه بزنید و نگه دارید."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏%1$d عرض در %2$d طول"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>، %2$d عرض در %3$d ارتفاع"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ابزارک را لمس کنید و نگه دارید تا بتوانید آن را در صفحه اصلی حرکت دهید"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"افزودن به صفحه اصلی"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g> به صفحه اصلی اضافه شد"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"پیشنهادها"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"بایدها"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"اخبار و مجله"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"منطقه آرامش شما"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"سرگرمی"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"سلامتی و تناسب اندام"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"آب‌وهوا"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارک‌های <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینه‌ها در سمت راست"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‏# ابزارک}one{‏# ابزارک}other{‏# ابزارک}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‏# میان‌بر}one{‏# میان‌بر}other{‏# میان‌بر}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"کار"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"مکالمه‌ها"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"یادداشت‌برداری"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"افزودن"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"افزودن ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"دسترسی آسان به اطلاعات سودمند"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"با افزودن ابزارک‌ها به صفحه اصلی می‌توانید اطلاعات را بدون باز کردن برنامه‌ها دریافت کنید"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"برای تغییر تنظیمات ابزارک، ضربه بزنید"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"برداشتن"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"حذف نصب"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"اطلاعات برنامه"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"نصب در نمایه خصوصی"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> درحال نصب است، <xliff:g id="PROGRESS">%2$s</xliff:g> تکمیل شده است"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"درحال بارگیری <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="PROGRESS">%2$s</xliff:g> کامل شد"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> درانتظار نصب"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> بایگانی شده است. برای بارگیری ضربه بزنید."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"برنامه باید به‌روز شود"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"برنامه برای این نماد به‌روز نشده است. می‌توانید آن را به‌صورت دستی به‌روز کنید تا میان‌بر دوباره فعال شود، یا نماد را بردارید."</string>
     <string name="dialog_update" msgid="2178028071796141234">"به‌روزرسانی"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"کاهش ارتفاع"</string>
     <string name="widget_resized" msgid="9130327887929620">"اندازه ابزارک به عرض <xliff:g id="NUMBER_0">%1$s</xliff:g> ارتفاع <xliff:g id="NUMBER_1">%2$s</xliff:g> تغییر کرد"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"میان‌برها"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"میان‌برها و اعلان‌ها"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"رد کردن"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"اعلان رد شد"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"کاری"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فیلتر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"فضای خصوصی"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"برای راه‌اندازی یا باز کردن، ضربه بزنید"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"قفل کردن"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"انتقال «فضای خصوصی»"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"نصب برنامه‌ها"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"نصب برنامه‌ها در «فضای خصوصی»"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"سرریز"</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 87e3040..9cb07fb 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Tallenna sovelluspari"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Sovellusparia ei tueta tällä laitteella"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Avaa taitettu laite, niin voit käyttää sovellusparia"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Sovelluspari ei ole saatavilla"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Kosketa pitkään, niin voit siirtää widgetiä."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Kaksoisnapauta ja paina pitkään, niin voit siirtää widgetiä tai käyttää muokattuja toimintoja."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Leveys: %1$d, korkeus: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, leveys %2$d ja korkeus %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Voit siirtää widgetiä aloitusnäytöllä koskettamalla sitä pitkään"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lisää aloitusnäytölle"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget lisätty aloitusnäytölle: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ehdotukset"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaikki tarvittava"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uutiset ja aikakauslehdet"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ota rennosti"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Viihde"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosiaalinen"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Terveys ja kuntoilu"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Sää"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sinulle ehdotetut"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgetit oikealla, haku ja vaihtoehdot vasemmalla"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetiä}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pikakuvake}other{# pikakuvaketta}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Työ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Keskustelut"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Muistiinpanojen tekeminen"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Lisää"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lisää widget: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Hyödyllisiä tietoja käden ulottuvilla"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Jos haluat nähdä tietoja avaamatta sovelluksia, voit lisätä aloitusnäytölle widgetejä"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Napauta, niin voit muuttaa widgetin asetuksia"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Poista"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Sovelluksen tiedot"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Asenna yksityisesti"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> asennetaan, <xliff:g id="PROGRESS">%2$s</xliff:g> valmis"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> latautuu, valmiina <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> odottaa asennusta"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> on arkistoitu. Lataa napauttamalla."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Sovelluspäivitys vaaditaan"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Kuvakkeen sovellusta ei ole päivitetty. Voit ottaa pikakuvakkeen uudelleen käyttöön päivittämällä sovelluksen tai poistaa kuvakkeen."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Päivitä"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Vähennä korkeutta"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetin kokoa muutettiin. Sen leveys on nyt <xliff:g id="NUMBER_0">%1$s</xliff:g> ja korkeus <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pikakuvakkeet"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pikakuvakkeet ja ilmoitukset"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hylkää"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Sulje"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Ilmoitus hylätty"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Henkilökohtaiset"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Työsovellukset"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Työprofiili"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Suodatin"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Yksityinen tila"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Ota käyttöön tai avaa napauttamalla"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Yksityinen"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lukko"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Yksityisen tilan siirtäminen"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Asenna sovelluksia"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Asenna sovelluksia yksityiseen tilaan"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ylivuoto"</string>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 0e8fe9c..0254d5e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -27,19 +27,32 @@
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets désactivés en mode sans échec"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"Le raccourci n\'est pas disponible"</string>
     <string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
-    <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
+    <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran divisé"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applications"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applications"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La Paire d\'applications n\'est pas offerte"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur sur %2$d de hauteur"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d de largeur sur %3$d de hauteur"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Maintenez le doigt sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a été ajouté à l\'écran d\'accueil"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentiels"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zone de divertissement"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Médias sociaux"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Santé et mise en forme"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Météo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggestions personnalisées"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à droite, recherche et options à gauche"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Professionnels"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de note"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Renseignements utiles à portée de main"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des informations sans ouvrir d\'applications, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Touchez pour modifier les paramètres du widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer dans privé"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
@@ -107,7 +123,7 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Cette fonction est désactivée par votre administrateur"</string>
     <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="notification_dots_title" msgid="9062440428204120317">"Points de notification"</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>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"L\'accès aux notifications est requis"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installation de l\'application <xliff:g id="NAME">%1$s</xliff:g> en cours, <xliff:g id="PROGRESS">%2$s</xliff:g> terminée"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Téléchargement de <xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"L\'application <xliff:g id="NAME">%1$s</xliff:g> est archivée. Toucher pour télécharger."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'application requise"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"L\'application pour cette icône n\'est pas à jour. Vous pouvez soit la mettre à jour manuellement pour réactiver ce raccourci, soit retirer l\'icône."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Mettre à jour"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
     <string name="widget_resized" msgid="9130327887929620">"Le widget a été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Raccourcis"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Raccourcis et notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorer"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Fermer"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification ignorée"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personnel"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toucher pour configurer ou ouvrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transition vers l\'Espace privé"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installer des applications"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applications dans l\'Espace privé"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu à développer"</string>
 </resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 9aa6ad2..1329a16 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applis"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Dépliez l\'appareil pour utiliser cette paire d\'applications"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La paire d\'applications n\'est pas disponible"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Appuyez de manière prolongée sur un widget pour le déplacer."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Appuyez deux fois et maintenez la pression pour déplacer widget ou utiliser actions personnalisées."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur et %2$d de hauteur"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d de large par %3$d de haut"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Appuyez de manière prolongée sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Les bases"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Réseaux sociaux"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Santé et bien-être"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Météo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Recommandations"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à droite, recherche et options à gauche"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Professionnels"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversations"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Prise de notes"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Ajouter"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez un widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Infos utiles à portée de main"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Pour obtenir des infos sans ouvrir d\'applis, vous pouvez ajouter des widgets à votre écran d\'accueil"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Appuyez pour modifier les paramètres du widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'application"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
@@ -108,8 +124,8 @@
     <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="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>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activées"</string>
+    <string name="notification_dots_desc_off" msgid="1760796511504341095">"Désactivées"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Accès aux notifications requis"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les pastilles de notification, activez les notifications de l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installation de <xliff:g id="NAME">%1$s</xliff:g>… (<xliff:g id="PROGRESS">%2$s</xliff:g> terminés)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> en cours de téléchargement, <xliff:g id="PROGRESS">%2$s</xliff:g> effectué(s)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"L\'application <xliff:g id="NAME">%1$s</xliff:g> est archivée. Appuyez pour télécharger."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'appli requise"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"L\'appli correspondant à cette icône n\'est pas mise à jour. Vous pouvez la mettre à jour manuellement pour réactiver le raccourci ou supprimer l\'icône."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Modifier"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuer la hauteur"</string>
     <string name="widget_resized" msgid="9130327887929620">"Le widget a bien été redimensionné (largeur : <xliff:g id="NUMBER_0">%1$s</xliff:g>, hauteur : <xliff:g id="NUMBER_1">%2$s</xliff:g>)."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Raccourcis"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Raccourcis et notifications"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorer"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Fermer"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notification ignorée"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personnel"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Professionnel"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Appuyer pour ouvrir ou configurer"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transition vers Espace privé"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installer applis"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applis dans l\'espace privé"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dépassement"</string>
 </resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 4eda3cf..4466c6d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Gardar emparellamento de aplicacións"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de apps"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"O dispositivo non admite este emparellamento de aplicacións"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desprega o dispositivo para usar este emparellamento de aplicacións"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Non está dispoñible o emparellamento de aplicacións"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén premido un widget para movelo."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dúas veces un widget e manteno premido para movelo ou utiliza accións personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largo por %2$d de alto"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>: %2$d de largo por %3$d de alto"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premido o widget para movelo pola pantalla de inicio"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Engadir á pantalla de inicio"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Engadiuse o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> á pantalla de inicio"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suxestións"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Esenciais"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias e revistas"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Reláxate"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretemento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociais"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e forma física"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"O tempo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suxestións personalizadas"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> á dereita, busca e opcións á esquerda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atallo}other{# atallos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Widgets do traballo"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Toma de notas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Engadir"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Engadir o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Información útil ao teu alcance"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Se queres obter información sen abrir as aplicacións, podes engadir widgets á pantalla de inicio"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toca para cambiar a configuración do widget"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicacións de traballo"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicación"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir aplicación"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
@@ -108,7 +124,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Permitir xirar a pantalla de inicio"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Ao xirar o teléfono"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Puntos de notificacións"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Activados"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Opción activada"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivados"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Necesítase acceso ás notificacións"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Para que se mostren os puntos de notificacións, activa as notificacións da aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> completado"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Descargando <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="PROGRESS">%2$s</xliff:g> completado)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Esperando para instalar <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> está no arquivo. Toca para descargar esta aplicación."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"É necesario actualizar a aplicación"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"A aplicación á que corresponde esta icona non está actualizada. Podes actualizala manualmente para activar de novo este atallo, ou ben quitar a icona."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Actualizar"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reducir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Cambiouse o tamaño do widget polo ancho <xliff:g id="NUMBER_0">%1$s</xliff:g> e a altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atallos"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atallos e notificacións"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Pechar"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Pechar"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Ignorouse a notificación"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persoal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Traballo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de traballo"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espazo privado"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toca para configuralo ou abrilo"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transición ao espazo privado"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar as aplicacións no espazo privado"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú adicional"</string>
 </resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index deaee86..931c38a 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ઍપની જોડી સાચવો"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"આ ડિવાઇસ પર, આ ઍપની જોડીને સપોર્ટ આપવામાં આવતો નથી"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"આ ઍપની જોડીનો ઉપયોગ કરવા માટે, ડિવાઇસને અનફોલ્ડ કરો"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ઍપની જોડી ઉપલબ્ધ નથી"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"વિજેટ ખસેડવા ટચ કરીને થોડી વાર દબાવી રાખો."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"વિજેટ ખસેડવા બે વાર ટૅપ કરીને દબાવી રાખો અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરો."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d પહોળાઈ X %2$d ઊંચાઈ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ, %2$d પહોળું x %3$d ઊંચું"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"વિજેટને હોમ સ્ક્રીનની આજુબાજુ ખસેડવા માટે, તેને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"હોમ સ્ક્રીનમાં ઉમેરો"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"હોમ સ્ક્રીન પર <xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેર્યુ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"સૂચનો"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"આવશ્યક"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ન્યૂઝ અને સામાયિકો"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"તમારો આરામદાયક ઝોન"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"મનોરંજન"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"સામાજિક"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"આરોગ્ય અને ફિટનેસ"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"હવામાન"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"તમારા માટે સૂચવેલી સેવાઓ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>ની વિજેટ જમણે, શોધ અને વિકલ્પો ડાબે"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# વિજેટ}one{# વિજેટ}other{# વિજેટ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# શૉર્ટકટ}one{# શૉર્ટકટ}other{# શૉર્ટકટ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ઑફિસ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"વાતચીતો"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"નોંધ લેવી"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ઉમેરો"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેરો"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ઉપયોગી માહિતી તમારી આંગળીના ટેરવે"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ઍપને ખોલ્યા વિના માહિતી મેળવવા માટે, તમે તમારી હોમ સ્ક્રીનમાં વિજેટ ઉમેરી શકો છો"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"વિજેટના સેટિંગ બદલવા માટે ટૅપ કરો"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"કાઢી નાખો"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટૉલ કરો"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપની માહિતી"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ખાનગીમાં ઇન્સ્ટૉલ કરો"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ઇન્સ્ટૉલ કરી રહ્યાં છીએ, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ થયું"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ડાઉનલોડ કરી રહ્યાં છે, <xliff:g id="PROGRESS">%2$s</xliff:g> પૂર્ણ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>, ઇન્સ્ટૉલ થવાની રાહ જોઈ રહ્યું છે"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> આર્કાઇવ કરી છે. ડાઉનલોડ કરવા માટે ટૅપ કરો."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ઍપને અપડેટ કરવી જરૂરી છે"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"આ આઇકન માટે ઍપ અપડેટ કરવામાં આવી નથી. તમે આ શૉર્ટકટ ફરી ચાલુ કરવા અથવા આઇકન કાઢી નાખવા માટે ઍપને મેન્યુઅલી અપડેટ કરી શકો છો."</string>
     <string name="dialog_update" msgid="2178028071796141234">"અપડેટ કરો"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ઊંચાઈ ઘટાડો"</string>
     <string name="widget_resized" msgid="9130327887929620">"વિજેટનો આકાર બદલીને <xliff:g id="NUMBER_0">%1$s</xliff:g> પહોળાઈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ઊંચાઈ કર્યો"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"શૉર્ટકટ્સ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"શૉર્ટકટ અને નોટિફિકેશનો"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"છોડી દો"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"બંધ કરો"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"વ્યક્તિગત ઍપ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ઑફિસની ઍપ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ઑફિસની પ્રોફાઇલ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ફિલ્ટર કરો"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"નિષ્ફળ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ખાનગી સ્પેસ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"સેટઅપ કરવા કે ખોલવા માટે ટૅપ કરો"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ખાનગી"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"લૉક"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ખાનગી સ્પેસ પર સ્થાનાંતરણ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ઍપ ઇન્સ્ટૉલ કરો"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ખાનગી સ્પેસમાં ઍપ ઇન્સ્ટૉલ કરો"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ઓવરફ્લો"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 52bc50a..600cde4 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"साथ में इस्तेमाल किए जा सकने वाले ऐप्लिकेशन की जानकारी सेव करें"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"ऐप पेयर सेव करें"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन, इस डिवाइस पर काम नहीं कर सकते"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन इस्तेमाल करने के लिए डिवाइस को अनफ़ोल्ड करें"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"साथ में इस्तेमाल किए जा सकने वाले ऐप्लिकेशन की सुविधा उपलब्ध नहीं है"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उसे दबाकर रखें."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उस पर दो बार टैप करके दबाकर रखें या पसंद के मुताबिक कार्रवाइयां इस्तेमाल करें."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौड़ाई गुणा %2$d ऊंचाई"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट. यह %2$d चौड़ा और %3$d लंबा है"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"विजेट को होम स्क्रीन पर इधर-उधर ले जाने के लिए, उसे दबाकर रखें"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रीन पर जोड़ें"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट को होम स्क्रीन पर जोड़ा गया"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"सुझाव"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ज़रूरी ऐप्लिकेशन"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"खबरों और पत्रिकाओं वाले ऐप्लिकेशन"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"आपके मनोरंजन के लिए"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"हेल्थ और फ़िटनेस वाले ऐप्लिकेशन"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"मौसम"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> के विजेट दाईं ओर, खोज का विजेट और अन्य विकल्प बाईं ओर"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"वर्क विजेट"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"बातचीत"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"नोट बनाने से जुड़े विजेट"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"जोड़ें"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोड़ें"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"काम की जानकारी आसानी से पाएं"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ऐप्लिकेशन को खोले बिना उनकी जानकारी पाने के लिए, होम स्क्रीन पर विजेट जोड़े जा सकते हैं"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट की सेटिंग में बदलाव करने के लिए टैप करें"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"हटाएं"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करें"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ऐप्लिकेशन की जानकारी"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी तौर पर इंस्टॉल करें"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्‍टॉल करें"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप्लिकेशन को पिन करें"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल किया जा रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा हो गया"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड हो रहा है, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरी हुई"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> के इंस्टॉल होने की प्रतीक्षा की जा रही है"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> को संग्रहित किया गया. डाउनलोड करने के लिए टैप करें."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ऐप्लिकेशन को अपडेट करना ज़रूरी है"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"इस आइकॉन का ऐप्लिकेशन अपडेट नहीं है. इस शॉर्टकट को फिर से चालू करने या आइकॉन को हटाने के लिए, ऐप्लिकेशन को मैन्युअल रूप से अपडेट किया जा सकता है."</string>
     <string name="dialog_update" msgid="2178028071796141234">"अपडेट करें"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ऊंचाई घटाएं"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेट का आकार बदलकर उसकी चौड़ाई <xliff:g id="NUMBER_0">%1$s</xliff:g> और ऊंचाई <xliff:g id="NUMBER_1">%2$s</xliff:g> कर दी गई"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"शॉर्टकट"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"शॉर्टकट और सूचनाएं"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारिज करें"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"बंद करें"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"सूचना को खारिज किया गया"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"निजी ऐप्लिकेशन"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"वर्क ऐप्लिकेशन"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"वर्क प्रोफ़ाइल"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फ़िल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"पूरा नहीं हुआ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"प्राइवेट स्पेस"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"सेट अप करने या खोलने के लिए टैप करें"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"प्राइवेट स्पेस की सेटिंग में बदलाव किया जा रहा है"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ऐप्लिकेशन इंस्टॉल करें"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"प्राइवेट स्पेस में ऐप्लिकेशन इंस्टॉल करें"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओवरफ़्लो"</string>
 </resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 9694428..e860ea9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Spremi par aplikacija"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Taj par aplikacija nije podržan na ovom uređaju"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Otvorite uređaj da biste upotrebljavali ovaj par aplikacija"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da biste premjestili widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite pritisak da biste premjestili widget ili upotrijebite prilagođene radnje"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d širine i %2$d visine"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, širine %2$d, visine %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite widget da biste ga pomicali po početnom zaslonu"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni zaslon"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> dodan je na početni zaslon"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovno"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Vijesti i časopisi"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša zona za opuštanje"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Društvene mreže"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdravlje i fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Vrijeme"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Prijedlozi za vas"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> –widgeti zdesna, pretraživanje i opcije slijeva"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}few{# widgeta}other{# widgeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečac}one{# prečac}few{# prečaca}other{# prečaca}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Razgovori"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pisanje bilježaka"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Da biste dobili informacije bez otvaranja aplikacija, možete dodati widgete na početni zaslon"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promijenili postavke widgeta"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliranje u privatni profil"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> dovršeno"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Preuzimanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>, dovršeno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Čekanje na instaliranje aplikacije <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> je arhivirana. Dodirnite za preuzimanje."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Aplikacija se treba ažurirati"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija ove ikone nije ažurirana. Možete ručno ažurirati da biste ponovo omogućili ovaj prečac ili uklonite ikonu."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Smanjenje visine"</string>
     <string name="widget_resized" msgid="9130327887929620">"Širina widgeta promijenjena je na <xliff:g id="NUMBER_0">%1$s</xliff:g>, a visina na <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečaci"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečaci i obavijesti"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zatvori"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Obavijest je odbačena"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobno"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Posao"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Poslovni profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste postavili ili otvorili"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključavanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prelazak na privatni prostor"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalirajte aplikacije"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dodatni izbornik"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 7c83ec0..03a30c4 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Alkalmazáspár mentése"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ezt az alkalmazáspárt nem támogatja az eszköz"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Hajtsa ki az eszközt az alkalmazáspár használatához"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Az alkalmazáspár nem áll rendelkezésre"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tartsa lenyomva a modult az áthelyezéshez."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Modul áthelyezéséhez koppintson duplán, tartsa nyomva az ujját, vagy használjon egyéni műveleteket."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d széles és %2$d magas"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul – %2$d széles, %3$d magas"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tartsa lenyomva a modult a kezdőképernyőn való mozgatáshoz"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Hozzáadás a kezdőképernyőhöz"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Legfontosabbak"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Újságok és magazinok"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Az Ön relaxáló zónája"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Szórakozás"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Közösségi"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Egészség és fitnesz"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Időjárás"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Neked javasolt"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"A <xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-modulok a jobb, a kereső és a beállítások pedig a bal oldalon találhatók"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# modul}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# gyorsparancs}other{# gyorsparancs}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Munka"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Beszélgetések"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Jegyzetelés"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Hozzáadás"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadása"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Hasznos információk egy koppintásnyira"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Ha az alkalmazások megnyitása nélkül szeretne információhoz jutni, felvehet modulokat a kezdőképernyőre"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ide koppintva módosíthatja a modulbeállításokat"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Törlés"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinfó"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Telepítés privátra"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon alkalmazást"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Folyamatban van a(z) <xliff:g id="NAME">%1$s</xliff:g> telepítése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"A(z) <xliff:g id="NAME">%1$s</xliff:g> letöltése, <xliff:g id="PROGRESS">%2$s</xliff:g> kész"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A(z) <xliff:g id="NAME">%1$s</xliff:g> telepítésre vár"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> archiválva. Koppintson a letöltéshez."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Alkalmazásfrissítés szükséges"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Az ikonhoz tartozó alkalmazás nincs frissítve. A parancsikon újbóli engedélyezéséhez frissítse az alkalmazást, vagy távolítsa ez az ikont."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Frissítés"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Magasság csökkentése"</string>
     <string name="widget_resized" msgid="9130327887929620">"Modul átméretezve <xliff:g id="NUMBER_0">%1$s</xliff:g> szélességre és <xliff:g id="NUMBER_1">%2$s</xliff:g> magasságra"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Gyorsparancsok"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Parancsikonok és értesítések"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Elvetés"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Bezárás"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Értesítés elvetve"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Személyes"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Munkahelyi"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Munkaprofil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Szűrő"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zárolás"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Átállás privát területre…"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"App telepítése"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Alkalmazások telepítése magánterületre"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Túlcsordulás"</string>
 </resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 7aa432b..0f65295 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվածների զույգը"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվ. զույգը"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Բացեք սարքը՝ այս հավելվածների զույգն օգտագործելու համար"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Հավելվածների զույգը հասանելի չէ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Հպեք և պահեք՝ վիջեթ տեղափոխելու համար։"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Կրկնակի հպեք և պահեք՝ վիջեթ տեղափոխելու համար, կամ օգտվեք հատուկ գործողություններից։"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Լայնությունը՝ %1$d, բարձրությունը՝ %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթ"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթ, լայնությունը՝ %2$d, բարձրությունը՝ %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Հպեք վիջեթին և պահեք՝ հիմնական էկրան տեղափոխելու համար"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ավելացնել հիմնական էկրանին"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթն ավելացվել է հիմնական էկրանին"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Առաջարկներ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Հիմնական"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Նորություններ և ամսագրեր"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ձեր հանգստի գոտին"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Զվարճանք"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Սոցցանցեր"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Առողջություն և ֆիթնես"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Եղանակ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Առաջարկում ենք"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"«<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>» հավելվածի վիջեթներն աջ կողմում են, իսկ որոնման դաշտը և կարգավորումները՝ ձախ կողմում"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# վիջեթ}one{# վիջեթ}other{# վիջեթ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# դյուրանցում}one{# դյուրանցում}other{# դյուրանցում}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Աշխատանքային"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Զրույցներ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Նշումների ստեղծում"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Ավելացնել"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Ավելացնել <xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթը"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Բոլոր կարևոր տեղեկությունները՝ ձեռքի տակ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Ավելացրեք վիջեթներ ձեր հիմնական էկրանին, որպեսզի տեղեկություններ ստանաք՝ առանց հավելվածները բացելու։"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Հպեք՝ վիջեթի կարգավորումները փոփոխելու համար"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Հեռացնել"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ապատեղադրել"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի մասին"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել անձնականում"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> հավելվածը տեղադրվում է, կատարված է <xliff:g id="PROGRESS">%2$s</xliff:g>-ը"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>–ի ներբեռնում (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>-ի տեղադրման սպասում"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> հավելվածն արխիվացված է։ Հպեք՝ ներբեռնելու համար:"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Պահանջվում է թարմացնել հավելվածը"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Հավելվածը հնացել է։ Թարմացրեք այն ձեռքով, որպեսզի շարունակեք օգտագործել դյուրանցումը, կամ հեռացրեք հավելվածի պատկերակը։"</string>
     <string name="dialog_update" msgid="2178028071796141234">"Թարմացնել"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Նվազեցնել բարձրությունը"</string>
     <string name="widget_resized" msgid="9130327887929620">"Վիջեթի լայնությունը փոխվել է <xliff:g id="NUMBER_0">%1$s</xliff:g>-ի, իսկ բարձրությունը՝ <xliff:g id="NUMBER_1">%2$s</xliff:g>-ի"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Դյուրանցումներ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Դյուրանցումներ և ծանուցումներ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Անտեսել"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Փակել"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Ծանուցումը մերժված է"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Անձնական"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Աշխատանքային"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Աշխատանքային պրոֆիլ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Զտեք"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Անձնական տարածք"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Անձնական"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Հպեք կարգավորելու կամ բացելու համար"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Մասնավոր"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել անձնական տարածքը"</string>
-    <string name="ps_container_transition" msgid="8667331812048014412">"Անցում անձնական տարածք"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել մասնավոր տարածքը"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Կողպում"</string>
+    <string name="ps_container_transition" msgid="8667331812048014412">"Անցում մասնավոր տարածք"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Հավելվածների տեղադրում"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Հավելվածների տեղադրում անձնական տարածքում"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Լրացուցիչ ընտրացանկ"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index b7ce5e3..c678e41 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Simpan pasangan aplikasi"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Pasangan aplikasi ini tidak didukung di perangkat ini"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bentangkan perangkat untuk menggunakan pasangan aplikasi ini"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Pasangan aplikasi tidak tersedia"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh lama untuk memindahkan widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketuk dua kali &amp; tahan untuk memindahkan widget atau gunakan tindakan khusus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, lebar %2$d dan tinggi %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh lama widget untuk memindah-mindahkannya di layar utama"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan ke layar utama"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan ke layar utama"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Saran"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Penting"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Berita &amp; majalah"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona Nyaman Anda"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hiburan"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosial"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kesehatan &amp; kebugaran"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Cuaca"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Disarankan untuk Anda"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> di bagian kanan, penelusuran dan opsi di bagian kiri"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kerja"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Percakapan"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pembuatan catatan"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Tambahkan"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Info bermanfaat mudah dilihat"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan info tanpa membuka aplikasi, Anda dapat menambahkan widget ke layar utama"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketuk untuk mengubah setelan widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hapus"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal secara pribadi"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan aplikasi"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
@@ -87,7 +103,7 @@
     <string name="gadget_setup_text" msgid="8348374825537681407">"Setelan widget"</string>
     <string name="gadget_complete_setup_text" msgid="309040266978007925">"Ketuk untuk menyelesaikan penyiapan"</string>
     <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat di-uninstal."</string>
-    <string name="folder_hint_text" msgid="5174843001373488816">"Sunting Nama"</string>
+    <string name="folder_hint_text" msgid="5174843001373488816">"Edit Nama"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dinonaktifkan"</string>
     <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} memiliki # notifikasi}other{{app_name} memiliki # notifikasi}}"</string>
     <string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> sedang diinstal, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> sedang didownload, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu dipasang"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> diarsipkan. Ketuk untuk mendownload."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Aplikasi perlu diupdate"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikasi untuk ikon ini belum diupdate. Anda dapat mengupdate secara manual untuk mengaktifkan kembali pintasan ini, atau hapus ikon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Kurangi tinggi"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget diubah ukurannya menjadi lebar <xliff:g id="NUMBER_0">%1$s</xliff:g> tinggi <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pintasan dan notifikasi"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Tutup"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Tutup"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notifikasi ditutup"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pribadi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Ketuk untuk menyiapkan atau membuka"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Pribadi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Ruang Pribadi Bertransisi"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instal aplikasi"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal aplikasi ke Ruang Pribadi"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu tambahan"</string>
 </resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 4ba0623..73a7d64 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Vista forritapar"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Þetta forritapar er ekki stutt í þessu tæki"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Opnaðu tæki til að nota þetta forritapar"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Forritapar er ekki í boði"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Haltu fingri á græju til að færa hana."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ýttu tvisvar og haltu fingri á græju til að færa hana eða notaðu sérsniðnar aðgerðir."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d á breidd og %2$d á hæð"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Græjan <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Græjan <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d breið og %3$d há"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Haltu fingri á græjunni til að hreyfa hana um heimaskjáinn"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Bæta á heimaskjá"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> græju bætt við heimaskjá"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Tillögur"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Það nauðsynlegasta"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Fréttir og tímarit"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Slakaðu á"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Afþreying"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Samfélag"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Heilsa og líkamsrækt"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Veður"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Tillögur fyrir þig"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-græjur til hægri, leit og valkostir til vinstri"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# græja}one{# græja}other{# græjur}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# flýtileið}one{# flýtileið}other{# flýtileiðir}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Vinna"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Samtöl"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Glósugerð"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Bæta við"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Bæta græjunni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> við"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Gagnlegar upplýsingar innan seilingar"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Þú getur bætt við græjum á heimaskjáinn til að fá upplýsingar án þess að opna forrit"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ýttu til að breyta græjustillingum"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Taka niður"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Forritsupplýsingar"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Setja upp á lokuðum prófíl"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Setur upp <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> í niðurhali, <xliff:g id="PROGRESS">%2$s</xliff:g> lokið"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> bíður uppsetningar"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> er í geymslu. Ýttu til að sækja."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Uppfæra þarf forritið"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Forritið fyrir þetta tákn er ekki uppfært. Þú getur uppfært það handvirkt til að kveikja aftur á þessari flýtileið eða fjarlægt táknið."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Uppfæra"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Minnka hæð"</string>
     <string name="widget_resized" msgid="9130327887929620">"Stærð græju breytt í <xliff:g id="NUMBER_0">%1$s</xliff:g> á breidd og <xliff:g id="NUMBER_1">%2$s</xliff:g> á hæð"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Flýtileiðir"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Flýtileiðir og tilkynningar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hunsa"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Loka"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Tilkynningu lokað"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Persónulegt"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Vinna"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Vinnusnið"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Sía"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Einkarými"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Ýttu til að setja upp eða opna"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsaeinkarými/taka einkarými úr lás"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsa leynirými/taka leynirými úr lás"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Læsa"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Setja upp forrit"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Setja upp forrit í leynirými"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Yfirflæði"</string>
 </resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 644d680..c32fec0 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Salva coppia di app"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Questa coppia di app non è supportata su questo dispositivo"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Apri il dispositivo per usare questa coppia di app"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"La coppia di app non è disponibile"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tocca e tieni premuto per spostare un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tocca due volte e tieni premuto per spostare un widget o per usare le azioni personalizzate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d di larghezza per %2$d di altezza"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d di larghezza per %3$d di altezza"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tocca e tieni premuto il widget per spostarlo nella schermata Home"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Aggiungi alla schermata Home"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> aggiunto alla schermata Home"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggerimenti"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essenziali"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Notizie e riviste"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Il tuo angolo di tranquillità"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Intrattenimento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salute e fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Consigliati per te"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget di <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a destra, ricerca e opzioni a sinistra"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# scorciatoia}other{# scorciatoie}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Lavoro"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversazioni"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Aggiunta di note"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Aggiungi"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Aggiungi widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informazioni utili a portata di mano"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Per ricevere informazioni senza aprire le app, puoi aggiungere dei widget alla schermata Home"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tocca per modificare le impostazioni del widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Rimuovi"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informazioni app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installa in privato"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Installazione di <xliff:g id="NAME">%1$s</xliff:g>, completamento: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Download di <xliff:g id="NAME">%1$s</xliff:g> in corso, <xliff:g id="PROGRESS">%2$s</xliff:g> completato"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> in attesa di installazione"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"App <xliff:g id="NAME">%1$s</xliff:g> archiviata. Tocca per scaricare."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"È necessario aggiornare l\'app"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"L\'app relativa a questa icona non è aggiornata. Puoi eseguire manualmente l\'aggiornamento per riattivare questa scorciatoia oppure rimuovere l\'icona."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Aggiorna"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Riduci altezza"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget ridimensionato a larghezza <xliff:g id="NUMBER_0">%1$s</xliff:g>, altezza <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Scorciatoie"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Scorciatoie e notifiche"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignora"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Esci"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notifica ignorata"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personali"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Lavoro"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profilo di lavoro"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Spazio privato"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocca per configurare o aprire"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privato"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Blocca"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transizione dello Spazio privato in corso…"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installa app"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installa le app su spazi privati"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Extra"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index c91e57c..88dce21 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"בית"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‏פרטים על האפליקציה %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"שמירה של צמד אפליקציות"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"שמירת צמד אפליקציות"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"צריך לפתוח את המכשיר כדי להשתמש בצמד האפליקציות הזה"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"צמד האפליקציות לא זמין"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏רוחב %1$d על גובה %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"ווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏ווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, רוחב: %2$d, אורך: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"לוחצים לחיצה ארוכה על הווידג\'ט כדי להזיז אותו במסך הבית"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"הוספה למסך הבית"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g> נוסף למסך הבית"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"הצעות"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"האפליקציות שחייבים להכיר"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"חדשות וכתבי עת"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"המקום שלך לרגיעה"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"בידור"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"רשתות חברתיות"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"בריאות וכושר"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"מזג אוויר"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"הצעות בשבילך"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"‫<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ווידג\'טים מימין, חיפוש ואפשרויות משמאל"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}one{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"עבודה"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"שיחות"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"כתיבת הערות"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"הוספה"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"הוספת הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"קבלת מידע שימושי בהקשה"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"רוצה לקבל מידע בלי לפתוח אפליקציות? אפשר להוסיף ווידג\'טים למסך הבית"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"אפשר לשנות את הגדרות הווידג\'ט בהקשה"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"הסרה"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"להסרת התקנה"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי אפליקציה"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"התקנה במרחב הפרטי"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
@@ -105,7 +121,7 @@
     <string name="edit_home_screen" msgid="8947858375782098427">"עריכה של מסך הבית"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"הגדרות של מסך הבית"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"הושבת על ידי מנהל המערכת שלך"</string>
-    <string name="allow_rotation_title" msgid="7222049633713050106">"אישור לסיבוב מסך הבית"</string>
+    <string name="allow_rotation_title" msgid="7222049633713050106">"סיבוב מסך הבית"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"כאשר מסובבים את הטלפון"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"סימני ההתראות"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"מופעל"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> בתהליך התקנה, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"הורדת <xliff:g id="NAME">%1$s</xliff:g> מתבצעת, <xliff:g id="PROGRESS">%2$s</xliff:g> הושלמו"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"מחכה להתקנה של <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"אפליקציית <xliff:g id="NAME">%1$s</xliff:g> הועברה לארכיון. יש להקיש כדי להוריד."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"נדרש עדכון לאפליקציה"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"האפליקציה של הסמל הזה לא מעודכנת. אפשר לעדכן אותה ידנית כדי להפעיל מחדש את קיצור הדרך הזה, או להסיר את הסמל."</string>
     <string name="dialog_update" msgid="2178028071796141234">"עדכון"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"הקטנת גובה"</string>
     <string name="widget_resized" msgid="9130327887929620">"גודל הווידג\'ט שונה - רוחב <xliff:g id="NUMBER_0">%1$s</xliff:g> גובה <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"קיצורי דרך"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"קיצורי דרך והתראות"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"סגירה"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"סגירה"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ההתראה נסגרה"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"אישי"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"עבודה"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"פרופיל עבודה"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"אפשר להקיש כדי להגדיר או לפתוח"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"פרטי"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"נעילה"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"מעבר למרחב הפרטי"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"התקנת אפליקציות"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"התקנת אפליקציות במרחב הפרטי"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"אפשרויות נוספות"</string>
 </resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 00b061f..d028e4e 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"アプリのペア設定を保存"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"このデバイスは、このアプリのペア設定に対応していません"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"このアプリのペア設定を使用するには、デバイスを開いてください"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"アプリのペア設定は利用できません"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"長押ししてウィジェットを移動させます。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ウィジェットをダブルタップして長押ししながら移動するか、カスタム操作を使用してください。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"幅 %1$d、高さ %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ウィジェット"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ウィジェット、幅%2$d、高さ%3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ウィジェットを押し続けると、ホーム画面上に移動できます"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ホーム画面に追加"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」ウィジェットをホーム画面に追加しました"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"候補"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"基本"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ニュース&雑誌"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"休憩エリア"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"エンタメ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ソーシャル"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"健康&フィットネス"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"天気"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"おすすめ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> のウィジェットは右側に、検索とオプションは左側にあります"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 件のウィジェット}other{# 件のウィジェット}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 件のショートカット}other{# 件のショートカット}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"仕事用"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"会話"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"メモ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"追加"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ウィジェットを追加"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ウィジェットで情報を得る"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ホーム画面にウィジェットを追加すると、アプリを開かずに情報を入手できます"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"タップしてウィジェットの設定を変更する"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"削除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"アンインストール"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"アプリ情報"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"非公開インストール"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
@@ -113,7 +129,7 @@
     <string name="title_missing_notification_access" msgid="7503287056163941064">"通知へのアクセス権限が必要"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"通知ドットを表示するには、「<xliff:g id="NAME">%1$s</xliff:g>」のアプリ通知を ON にしてください"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"設定を変更"</string>
-    <string name="notification_dots_service_title" msgid="4284221181793592871">"通知ドットの表示"</string>
+    <string name="notification_dots_service_title" msgid="4284221181793592871">"通知ドットを表示"</string>
     <string name="developer_options_title" msgid="700788437593726194">"開発者向けオプション"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"ホーム画面にアプリのアイコンを追加"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"新しいアプリをダウンロードしたときに自動で追加します"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> をインストールしています: <xliff:g id="PROGRESS">%2$s</xliff:g> 完了"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>をダウンロード中、<xliff:g id="PROGRESS">%2$s</xliff:g>完了"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>のインストール待ち"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> はアーカイブ済みです。ダウンロードするにはタップします。"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"アプリの更新が必要"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"このアイコンのアプリは更新されていません。手動で更新して、このショートカットを再度有効にできます。また、アイコンを削除することもできます。"</string>
     <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"高さを低くする"</string>
     <string name="widget_resized" msgid="9130327887929620">"ウィジェットのサイズを幅<xliff:g id="NUMBER_0">%1$s</xliff:g>、高さ<xliff:g id="NUMBER_1">%2$s</xliff:g>に変更しました"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ショートカット"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ショートカットと通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"表示しない"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"閉じる"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"通知を非表示にしました"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人用"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"仕事用"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"仕事用プロファイル"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"フィルタ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失敗: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"プライベート スペース"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"設定したり開いたりするにはタップしてください"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"プライベート"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ロック"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"プライベート スペース移行中"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"アプリをインストールする"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"プライベート スペースにアプリをインストールします"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"オーバーフロー"</string>
 </resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index d428447..e3b5627 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"აპთა წყვილის შენახვა"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ამ მოწყობილობაზე აღნიშნული აპთა წყვილი არ არის მხარდაჭერილი"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"გაშალეთ მოწყობილობა ამ აპთა წყვილის გამოსაყენებლად"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"აპთა წყვილი მიუწვდომელია"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ორმაგი შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"სიგრძე: %1$d, სიგანე: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტი"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტი, სიგანე: %2$d, სიმაღლე: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ხანგრძლივად შეეხეთ ვიჯეტს მთავარ ეკრანზე მის გადასაადგილებლად"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"მთავარ ეკრანზე დამატება"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტი დამატებულია მთავარ ეკრანზე"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"შეთავაზებები"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"უმნიშვნელოვანესები"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ახალი ამბები და ჟურნალები"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"განტვირთვის ადგილი"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"გართობა"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"სოციალური"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ჯანმრთელობა და ფიტნესი"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"ამინდი"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"თქვენთვის შემოთავაზებული"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ვიჯეტები მდებარეობს მარჯვნივ, ძებნა და პარამეტრები — მარცხნივ"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ვიჯეტი}other{# ვიჯეტი}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# მალსახმობი}other{# მალსახმობი}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"სამსახური"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"მიმოწერები"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ჩანიშვნა"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"დამატება"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტის დამატება"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ადვილად მისაწვდომი სასარგებლო ინფორმაცია"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"იმისთვის, რომ ინფორმაცია აპების გაუხსნელად მიიღოთ, შეგიძლიათ, მთავარ ეკრანზე ვიჯეტები დაამატოთ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"შეეხეთ ვიჯეტის პარამეტრების შესაცვლელად"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ამოშლა"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"პირადში ინსტალაცია"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"ინსტალირდება <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულებულია"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"მიმდინარეობს <xliff:g id="NAME">%1$s</xliff:g>-ის ჩამოტვირთვა, <xliff:g id="PROGRESS">%2$s</xliff:g> დასრულდა"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ელოდება ინსტალაციას"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> დაარქივებულია. შეეხეთ ჩამოსატვირთად."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"საჭიროა აპის განახლება"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ამ ხატულის აპი განახლებული არ არის. შეგიძლიათ, ხელით განაახლოთ ამ მალსახმობის ხელახლა გასააქტიურებლად, ან ამოშალოთ ხატულა."</string>
     <string name="dialog_update" msgid="2178028071796141234">"განახლება"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"სიმაღლის შემცირება"</string>
     <string name="widget_resized" msgid="9130327887929620">"ვიჯეტის ზომები შეიცვალა: სიგანე <xliff:g id="NUMBER_0">%1$s</xliff:g> სიმაღლე <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"მალსახმობები"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"მალსახმობები და შეტყობინებები"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"დახურვა"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"დახურვა"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"შეტყობინება დაიხურა"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"პირადი"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"სამსახური"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"სამსახურის პროფილი"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ფილტრი"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ვერ მოხერხდა: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"პირადი სივრცე"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"დასაყენებლად ან გასახსნელად შეეხეთ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"პირადი"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ჩაკეტვა"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"პირად სივრცეზე გადასვლა"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"აპების ინსტალაცია"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"კერძო სივრცეში აპების ინსტალაცია"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"გადავსება"</string>
 </resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 4f6c6fd..215ac74 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Қолданбаларды жұптау әрекетін сақтау"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бұл құрылғы қолданбаларды жұптау функциясын қолдамайды."</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Қолданбаларды жұптау функциясын пайдалану үшін құрылғыны ашыңыз."</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Қолданбаларды жұптау функциясы қолжетімді емес."</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетті жылжыту үшін басып тұрыңыз."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетті жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ені: %1$d, биіктігі: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Виджет: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>. Ені %2$d, биіктігі %3$d."</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Негізгі экран бойынша жылжыту үшін виджетті басып ұстаңыз."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Негізгі экранға қосу"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті негізгі экранға енгізілді."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ұсыныстар"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Ең қажетті"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Жаңалықтар мен журналдар"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Жанға жайлы жер"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Ойын-сауық"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Қоғам"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Денсаулық және фитнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ауа райы"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Сізге ұсынылғандар"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> виджеттері оң жақта, іздеу мен опциялар сол жақта"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# таңбаша}other{# таңбаша}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Жұмыс виджеттері"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Әңгімелер"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ескертпе жазу"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Қосу"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Виджет (<xliff:g id="WIDGET_NAME">%1$s</xliff:g>) қосу"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Саусақпен түртсеңіз болғаны – пайдалы ақпарат көз алдыңызда"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Қолданбаларды ашпай-ақ ақпарат алу үшін негізгі экранға тиісті виджеттерді қосыңыз."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджет параметрлерін өзгерту үшін түртіңіз."</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Алып тастау"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке профильге орнату"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнатылуда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктелуде, <xliff:g id="PROGRESS">%2$s</xliff:g> аяқталды"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнату күтілуде"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> мұрағатталды. Жүктеп алу үшін түртіңіз."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Қолданбаны жаңарту қажет"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Осы белгіше үшін қолданба жаңартылмаған. Оны қолмен жаңартып, осы таңбашаны қайта іске қоса аласыз немесе белгішені өшіріп тастаңыз."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Жаңарту"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Биіктігін азайту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджет өлшемінің ені <xliff:g id="NUMBER_0">%1$s</xliff:g>, биіктігі <xliff:g id="NUMBER_1">%2$s</xliff:g> болып өзгертілді"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Жылдам пәрмендер"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Таңбашалар мен хабарландырулар"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Бас тарту"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Жабу"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Хабарландырудан бас тартылды"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Жұмыс"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жұмыс профилі"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Сүзгі"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Жеке бөлме"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Реттеу немесе ашу үшін түртіңіз"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Құлыптау"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Жеке бөлмеге өту"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Қолданбалар орнату"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Қолданбаларды \"Құпия кеңістікке\" орнатыңыз."</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Қосымша мәзір"</string>
 </resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 91622f0..243f9f4 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធី​សម្រាប់ %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"រក្សាទុកគូកម្មវិធី"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"មិនអាចប្រើគូកម្មវិធីនេះនៅលើឧបករណ៍នេះបានទេ"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"លាឧបករណ៍ ដើម្បីប្រើគូកម្មវិធីនេះ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"មិនអាចប្រើគូកម្មវិធីបានទេ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ចុចឱ្យជាប់​ដើម្បីផ្លាស់ទី​ធាតុក្រាហ្វិក​។"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ចុចពីរដង រួចសង្កត់ឱ្យជាប់ ដើម្បីផ្លាស់ទី​ធាតុក្រាហ្វិក ឬប្រើ​សកម្មភាព​តាមបំណង​។"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ទទឺង %1$d គុណនឹងកម្ពស់ %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"ធាតុ​ក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"ធាតុ​ក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ទទឹង %2$d គុណនឹងកម្ពស់ %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ចុចលើធាតុក្រាហ្វិកឱ្យជាប់ ដើម្បីផ្លាស់ទីវាជុំវិញអេក្រង់ដើម"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"បញ្ចូល​ទៅក្នុង​អេក្រង់​ដើម"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"បានបញ្ចូល​ធាតុក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ទៅ​អេក្រង់ដើម"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ការណែនាំ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"សំខាន់"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ព័ត៌មាន និង​ទស្សនាវដ្ដី"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"តំបន់បន្ធូរ​អារម្មណ៍របស់អ្នក"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"កម្សាន្ត"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"សង្គម"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"សុខភាព និង​សម្បទា"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"អាកាសធាតុ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ណែនាំជូនអ្នក"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ធាតុក្រាហ្វិក <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> នៅខាងស្ដាំ ការស្វែងរក និងជម្រើសនៅខាងឆ្វេង"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ធាតុ​ក្រាហ្វិក #}other{ធាតុ​ក្រាហ្វិក #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ផ្លូវកាត់ #}other{ផ្លូវកាត់ #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ការងារ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ការសន្ទនា"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ការកត់ត្រា"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"បញ្ចូល"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"បញ្ចូលធាតុ​ក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ទទួលបាន​ព័ត៌មានដែលមានប្រយោជន៍​យ៉ាងងាយស្រួល"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ដើម្បីទទួលបាន​ព័ត៌មាន​ដោយមិនចាំបាច់​បើកកម្មវិធី អ្នកអាចបញ្ចូលធាតុ​ក្រាហ្វិកទៅក្នុង​អេក្រង់ដើម​របស់អ្នក"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ចុចដើម្បីប្ដូរការកំណត់ធាតុ​ក្រាហ្វិក"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"យកចេញ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុប"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ព័ត៌មាន​កម្មវិធី"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ដំឡើងជាលក្ខណៈឯកជន"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការ​ព្យាករ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"កំពុង​ដំឡើង <xliff:g id="NAME">%1$s</xliff:g>, បាន​បញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"កំពុងដោនឡូត <xliff:g id="NAME">%1$s</xliff:g> បានបញ្ចប់ <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> កំពុងរង់ចាំការដំឡើង"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ត្រូវបានទុក​ក្នុង​បណ្ណសារ។ សូមចុចដើម្បីទាញយក។"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"តម្រូវឱ្យមាន​កំណែកម្មវិធីថ្មី"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"កម្មវិធីសម្រាប់​រូបតំណាងនេះ​មិនត្រូវបានដំឡើងកំណែ​ទេ។ អ្នកអាច​ដំឡើងកំណែ​ដោយផ្ទាល់ ដើម្បីបើក​ផ្លូវកាត់នេះឡើងវិញ ឬលុបរូបតំណាងនេះ។"</string>
     <string name="dialog_update" msgid="2178028071796141234">"ដំឡើងកំណែ"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"បន្ថយកម្ពស់"</string>
     <string name="widget_resized" msgid="9130327887929620">"ធាតុក្រាហ្វិកដែលបានប្តូរទំហំទៅទទឹងប្រវែង <xliff:g id="NUMBER_0">%1$s</xliff:g> កម្ពស់ប្រវែង <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ផ្លូវកាត់"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ផ្លូវកាត់ និង​ការជូនដំណឹង"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ច្រានចោល"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"បិទ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"បាន​បដិសេធ​ការជូនដំណឹង"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ផ្ទាល់ខ្លួន"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ការងារ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"កម្រងព័ត៌មានការងារ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"តម្រង"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"បានបរាជ័យ៖ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"បន្ទប់​ឯកជន"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ចុចដើម្បីរៀបចំ ឬបើក"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ឯកជន"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ចាក់សោ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ការផ្លាស់ប្ដូរ Private Space"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ដំឡើង​កម្មវិធី"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ដំឡើងកម្មវិធីទៅលំហឯកជន"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ម៉ឺនុយបន្ថែម"</string>
 </resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index ad208f2..4ab4ada 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಜೋಡಿ ಉಳಿಸಿ"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯನ್ನು ಬಳಸಲು ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ಆ್ಯಪ್ ಜೋಡಿ ಲಭ್ಯವಿಲ್ಲ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ವಿಜೆಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ವಿಜೆಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ಅಗಲ ಮತ್ತು %2$d ಎತ್ತರ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್, %2$d ಅಗಲ ಮತ್ತು %3$d ಎತ್ತರ"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ ಸುತ್ತ ವಿಜೆಟ್ ಅನ್ನು ಸರಿಸಲು, ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಸೇರಿಸಿ"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ಹೋಮ್‌ಸ್ಕ್ರೀನ್‌ಗೆ <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಲಾಗಿದೆ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ಸಲಹೆಗಳು"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ಅಗತ್ಯತೆಗಳು"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ಸುದ್ದಿ ಮತ್ತು ನಿಯತಕಾಲಿಕೆಗಳು"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ನೀವು ವಿಶ್ರಾಂತಿ ಪಡೆಯುವ ಸ್ಥಳ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ಮನರಂಜನೆ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ಸಾಮಾಜಿಕ"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ಆರೋಗ್ಯ ಮತ್ತು ಫಿಟ್‌ನೆಸ್"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"ಹವಾಮಾನ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ನಿಮಗಾಗಿ ಸೂಚಿಸಲಾಗಿರುವುದು"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ಬಲಭಾಗದಲ್ಲಿ <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ವಿಜೆಟ್‌ಗಳು, ಎಡಭಾಗದಲ್ಲಿ ಹುಡುಕಾಟ ಮತ್ತು ಆಯ್ಕೆಗಳು"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ವಿಜೆಟ್}one{# ವಿಜೆಟ್‌ಗಳು}other{# ವಿಜೆಟ್‌ಗಳು}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ಶಾರ್ಟ್‌ಕಟ್}one{# ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು}other{# ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ಕೆಲಸ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ಸಂಭಾಷಣೆಗಳು"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ಟಿಪ್ಪಣಿ ತೆಗೆದುಕೊಳ್ಳುವುದು"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ಸೇರಿಸಿ"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಸೇರಿಸಿ"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ನಿಮ್ಮ ಬೆರಳ ತುದಿಯಲ್ಲಿ ಉಪಯುಕ್ತ ಮಾಹಿತಿ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ಆ್ಯಪ್‌ಗಳನ್ನು ತೆರೆಯದೆಯೇ ಮಾಹಿತಿಯನ್ನು ಪಡೆಯಲು, ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ನೀವು ವಿಜೆಟ್‌ಗಳನ್ನು ಸೇರಿಸಬಹುದು"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಪಟ್ಟಿ"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ಡೌನ್‌ಲೋಡ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ, <xliff:g id="PROGRESS">%2$s</xliff:g> ಪೂರ್ಣಗೊಂಡಿದೆ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ಸ್ಥಾಪಿಸಲು ಕಾಯಲಾಗುತ್ತಿದೆ"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ಅನ್ನು ಆರ್ಕೈವ್ ಮಾಡಲಾಗಿದೆ. ಡೌನ್‌ಲೋಡ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ಆ್ಯಪ್ ಅಪ್‌ಡೇಟ್ ಅಗತ್ಯವಿದೆ"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ಈ ಐಕಾನ್‌ಗಾಗಿ ಆ್ಯಪ್ ಅನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿಲ್ಲ. ಈ ಶಾರ್ಟ್‌ಕಟ್ ಅನ್ನು ಮರು-ಸಕ್ರಿಯಗೊಳಿಸಲು ನೀವು ಹಸ್ತಚಾಲಿತವಾಗಿ ಅಪ್‌ಡೇಟ್ ಮಾಡಬಹುದು ಅಥವಾ ಐಕಾನ್ ಅನ್ನು ತೆಗೆದುಹಾಕಬಹುದು."</string>
     <string name="dialog_update" msgid="2178028071796141234">"ಅಪ್‌ಡೇಟ್ ಮಾಡಿ"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ಎತ್ತರವನ್ನು ಕಡಿಮೆ ಮಾಡಿ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ವಿಜೆಟ್ ಅನ್ನು <xliff:g id="NUMBER_0">%1$s</xliff:g> ಅಗಲ <xliff:g id="NUMBER_1">%2$s</xliff:g> ಎತ್ತರಕ್ಕೆ ಮರುಗಾತ್ರಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು ಮತ್ತು ಅಧಿಸೂಚನೆಗಳು"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ವಜಾಗೊಳಿಸಿ"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ಮುಚ್ಚಿರಿ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ಅಧಿಸೂಚನೆಯನ್ನು ವಜಾಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ವೈಯಕ್ತಿಕ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ಕೆಲಸ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ಫಿಲ್ಟರ್‌"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ವಿಫಲವಾಗಿದೆ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ಸೆಟಪ್ ಮಾಡಲು ಅಥವಾ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ಖಾಸಗಿ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ಲಾಕ್ ಮಾಡಿ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಪರಿವರ್ತನೆಯಾಗುತ್ತಿದೆ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ಆ್ಯಪ್‌ಗಳನ್ನು ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ಆ್ಯಪ್‌ಗಳನ್ನು ಪ್ರೈವೇಟ್ ಸ್ಪೇಸ್‌ನಲ್ಲಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ಓವರ್‌ಫ್ಲೋ"</string>
 </resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b2b0c0c..42b12ab 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"앱 페어링 저장"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"이 앱 페어링은 이 기기에서 지원되지 않습니다"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"이 앱 페어링을 사용하려면 기기를 펼치세요"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"앱 페어링을 사용할 수 없습니다."</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"길게 터치하여 위젯을 이동하세요."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"두 번 탭한 다음 길게 터치하여 위젯을 이동하거나 맞춤 작업을 사용하세요."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"너비 %1$d, 높이 %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"위젯 <xliff:g id="WIDGET_NAME">%1$s</xliff:g>개"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯, 너비는 %2$d, 높이는 %3$d입니다"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"홈 화면에서 위젯을 이동하려면 길게 터치하세요."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"홈 화면에 추가"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯이 홈 화면에 추가됨"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"추천"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"필수"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"뉴스 및 잡지"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"휴식 공간"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"엔터테인먼트"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"소셜"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"건강 및 피트니스"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"날씨"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"추천"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"오른쪽에 <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> 위젯, 왼쪽에 검색 및 옵션"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{위젯 #개}other{위젯 #개}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{바로가기 #개}other{바로가기 #개}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"직장 위젯"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"대화"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"메모"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"추가"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯 추가"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"빠르게 유용한 정보 확인"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"앱을 열지 않고 정보를 확인하려면 홈 화면에 위젯을 추가하세요."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"탭하여 위젯 설정 변경"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"삭제"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"앱 정보"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 설치"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> 설치 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> 다운로드 중, <xliff:g id="PROGRESS">%2$s</xliff:g> 완료"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> 설치 대기 중"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> 앱이 보관처리되었습니다. 다운로드하려면 탭하세요."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"앱 업데이트 필요"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"바로가기 아이콘의 앱이 업데이트되지 않았습니다. 직접 업데이트하여 앱 바로가기를 다시 사용할 수 있도록 하거나 아이콘을 삭제하세요."</string>
     <string name="dialog_update" msgid="2178028071796141234">"업데이트"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"높이 줄이기"</string>
     <string name="widget_resized" msgid="9130327887929620">"폭 <xliff:g id="NUMBER_0">%1$s</xliff:g>, 높이 <xliff:g id="NUMBER_1">%2$s</xliff:g>로 위젯 크기 조정됨"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"바로가기"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"바로가기 및 알림"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"닫기"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"닫기"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"알림이 해제되었습니다."</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"개인"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"직장"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"직장 프로필"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"필터"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"실패: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"비공개 스페이스"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"탭하여 설정 또는 열기"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"비공개"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"잠금"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"비공개 스페이스 전환"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"앱 설치"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"비공개 스페이스에 앱 설치"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"오버플로"</string>
 </resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 78e96a6..f908299 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Башкы экран"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Эки колдонмону бир маалда пайдаланууну сактоо"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Колдонмолорду сактап коюу"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бул эки колдонмону бул түзмөктө бир маалда пайдаланууга болбойт"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Бул эки колдонмону бир маалда пайдалануу үчүн түзмөктү ачыңыз"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Эки колдонмону бир маалда пайдаланууга болбойт"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетти кое бербей басып туруп жылдырыңыз."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетти жылдыруу үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Туурасы: %1$d, бийиктиги: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети, кеңдиги %2$d жана бийиктиги %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Башкы экранга жылдыруу үчүн виджетти коё бербей басып туруңуз"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Башкы экранга кошуу"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети башкы экранга кошулду"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Сунуштар"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Эң зарыл параметрлер"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Жаңылыктар жана журналдар"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Чер жазуу"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Көңүл ачуу"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Коомдук тармактар"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Ден соолук жана дене-бойду чыңдоо"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Аба ырайы"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Сизге сунушталат"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> виджеттери оң, ал эми издөө жана параметрлер сол жакта"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ыкчам баскыч}other{# ыкчам баскыч}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Жумуш"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Сүйлөшүүлөр"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Эскертме жазуу"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Кошуу"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетин кошуу"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Керектүү маалымат манжаңыздын учунда"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Бир нерсе билүү үчүн колдонмолорду улам ачып убара болбостон, башкы экранга виджеттерди кошуп коюңуз."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Виджеттин параметрлерин өзгөртүү үчүн таптап коюңуз"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Өчүрүү"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Чыгарып салуу"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Колдонмо тууралуу"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке мейкиндикке орнотуу"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> орнотулууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аткарылды"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> жүктөлүп алынууда, <xliff:g id="PROGRESS">%2$s</xliff:g> аяктады"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> орнотулушу күтүлүүдө"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> архивделди. Жүктөп алуу үчүн тийип коюңуз."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Колдонмону жаңыртыңыз"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Бул сүрөтчөнүн колдонмосу жаңыртылган эмес. Ыкчам баскычты кайра иштетүү үчүн аны кол менен жаңыртып же сүрөтчөнү өчүрүп койсоңуз болот."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Жаңыртуу"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Жапыздатуу"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджеттин кеңдиги <xliff:g id="NUMBER_0">%1$s</xliff:g> бийиктиги <xliff:g id="NUMBER_1">%2$s</xliff:g> болду"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Кыска жолдор"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Кыска жолдор жана билдирмелер"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Этибарга албоо"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Жабуу"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Билдирме жабылды"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Жеке колдонмолор"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Жумуш колдонмолору"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Жумуш профили"</string>
@@ -173,10 +188,14 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Улантуу"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Чыпкалоо"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Жеке чөйрө"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Жеке мейкиндик"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Тууралоо же ачуу үчүн таптап коюңуз"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
-    <string name="ps_container_settings" msgid="6059734123353320479">"Жеке чөйрөнүн параметрлери"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке чөйрөнү кулпулоо/кулпусун ачуу"</string>
+    <string name="ps_container_settings" msgid="6059734123353320479">"Жеке мейкиндиктин параметрлери"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке мейкиндикти кулпулоо/кулпусун ачуу"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Кулпулоо"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Жеке чөйрөгө өтүү"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Колдонмолорду орнотуу"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Колдонмолорду Жеке мейкиндикке орнотуe"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Кошумча меню"</string>
 </resources>
diff --git a/res/values-ldrtl/strings.xml b/res/values-ldrtl/strings.xml
new file mode 100644
index 0000000..118b499
--- /dev/null
+++ b/res/values-ldrtl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- General -->
+    <skip />
+
+    <!-- accessibilityPaneTitle for the right pane when showing suggested widgets. -->
+    <string name="widget_picker_right_pane_accessibility_title"><xliff:g id="selected_header" example="Calendar">%1$s</xliff:g> widgets on left, search and options on right</string>
+</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index bb99150..c215bc8 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ການຈັບຄູ່ແອັບນີ້ບໍ່ຮອງຮັບຢູ່ອຸປະກອນນີ້"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ກາງອຸປະກອນອອກເພື່ອໃຊ້ການຈັບຄູ່ແອັບນີ້"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ການຈັບຄູ່ແອັບບໍ່ມີໃຫ້"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ແຕະຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ ຫຼື ໃຊ້ຄຳສັ່ງກຳນົດເອງ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ກວ້າງ %1$d ຄູນສູງ %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"ວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"ວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, ກວ້າງ %2$d ສູງ %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ແຕະໃສ່ວິດເຈັດຄ້າງໄວ້ເພື່ອຍ້າຍມັນໄປມາຢູ່ໂຮມສະກຣີນ"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ເພີ່ມໃສ່ໂຮມສະກຣີນ"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ໃສ່ໂຮມສະກຣີນແລ້ວ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ການແນະນຳ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ສິ່ງຈຳເປັນ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ຂ່າວ ແລະ ວາລະສານ"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ພື້ນທີ່ພັກຜ່ອນຂອງທ່ານ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ຄວາມບັນເທີງ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ສັງຄົມ"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ສຸຂະພາບ ແລະ ການອອກກຳລັງກາຍ"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"ສະພາບອາກາດ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ແນະນຳສຳລັບທ່ານ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ວິດເຈັດ <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ຢູ່ທາງຂວາ, ການຊອກຫາ ແລະ ຕົວເລືອກຢູ່ທາງຊ້າຍ"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ວິດເຈັດ}other{# ວິດເຈັດ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ທາງລັດ}other{# ທາງລັດ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ວຽກ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ການສົນທະນາ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ການຈົດບັນທຶກ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ເພີ່ມ"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ຂໍ້ມູນທີ່ເປັນປະໂຫຍດຢູ່ປາຍນິ້ວຂອງທ່ານ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ເພື່ອຮັບຂໍ້ມູນໂດຍບໍ່ຕ້ອງເປີດແອັບ, ທ່ານສາມາດເພີ່ມວິດເຈັດໃສ່ໂຮມສະກຣີນຂອງທ່ານໄດ້"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ແຕະເພື່ອປ່ຽນການຕັ້ງຄ່າວິດເຈັດ"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ເອົາ​ອອກ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ຖອນ​ການ​ຕິດ​ຕັ້ງ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ຂໍ້ມູນແອັບ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ຕິດຕັ້ງໃນສ່ວນຕົວ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"ກຳລັງຕິດຕັ້ງ <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳເລັດແລ້ວ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ດາວ​ໂຫຼດ, <xliff:g id="PROGRESS">%2$s</xliff:g> ສຳ​ເລັດ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ກຳ​ລັງ​ລໍ​ຖ້າ​ຕິດ​ຕັ້ງ"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ຖືກເກັບໄວ້ໃນແຟ້ມ. ແຕະເພື່ອດາວໂຫລດ."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ຈຳເປັນຕ້ອງອັບເດດແອັບ"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ບໍ່ໄດ້ອັບເດດແອັບສຳລັບໄອຄອນນີ້. ທ່ານສາມາດອັບເດດເອງໄດ້ເພື່ອເປີດການນຳໃຊ້ທາງລັດນີ້ຄືນໃໝ່ ຫຼື ລຶບໄອຄອນດັ່ງກ່າວອອກ."</string>
     <string name="dialog_update" msgid="2178028071796141234">"ອັບເດດ"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ຫຼຸດ​ລວງ​ສູງ​ລົງ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ປ່ຽນ​ຂະ​ໜາດ​ວິດ​ເຈັດ​ເປັນ​ລວງ​ກ້​ວາງ <xliff:g id="NUMBER_0">%1$s</xliff:g> ລວງ​ສູງ <xliff:g id="NUMBER_1">%2$s</xliff:g> ແລ້ວ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ທາງລັດ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ປຸ່ມລັດ ແລະ ການແຈ້ງເຕືອນ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ປິດໄວ້"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ປິດ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ປິດການແຈ້ງເຕືອນແລ້ວ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ສ່ວນຕົວ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ວຽກ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ກັ່ນຕອງ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ບໍ່ສຳເລັດ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ພື້ນທີ່ສ່ວນຕົວ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ແຕະເພື່ອຕັ້ງຄ່າ ຫຼື ເປີດ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ສ່ວນຕົວ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ລັອກ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ການປ່ຽນແປງພື້ນທີ່ສ່ວນຕົວ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ຕິດຕັ້ງແອັບ"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ຕິດຕັ້ງແອັບໄປໃສ່ພື້ນທີ່ສ່ວນບຸກຄົນ"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ການດຳເນີນການເພີ່ມເຕີມ"</string>
 </resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 075bbb2..fda9e95 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Išsaugoti programų porą"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ši programų pora šiame įrenginyje nepalaikoma"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Atlenkite įrenginį, kad galėtumėte naudoti šią programų porą."</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Programų pora nepasiekiama"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dukart pal. ir palaik., kad perkeltumėte valdiklį."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dukart palieskite ir palaikykite, kad perkeltumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plotis ir %2$d aukštis"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> valdiklis"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Valdiklis: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>; %2$d pločio ir %3$d aukščio"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Paliesdami ir palaikydami valdiklį galite judėti pagrindiniame ekrane"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pridėti prie pagrindinio ekrano"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Valdiklis „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ pridėtas prie pagrindinio ekrano"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Pasiūlymai"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Būtiniausi"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Naujienos ir žurnalai"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jūsų atsipalaidavimo zona"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Pramogos"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Socialiniai tinklai"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sveikata ir kūno rengyba"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Orai"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Siūloma jums"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> valdikliai dešinėje, paieška ir parinktys kairėje"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# valdiklis}one{# valdiklis}few{# valdikliai}many{# valdiklio}other{# valdiklių}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# spartusis klavišas}one{# spartusis klavišas}few{# spartieji klavišai}many{# sparčiojo klavišo}other{# sparčiųjų klavišų}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Darbas"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Pokalbiai"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Užrašų kūrimas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Pridėti"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridėti valdiklį: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Lengvai pasiekiama naudinga informacija"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Jei norite gauti informacijos neatidarę programų, galite pridėti valdiklių pagrindiniame ekrane"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Palieskite, kad pakeistumėte valdiklio nustatymus"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Pašalinti"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Pašalinti"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Programos inform."</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Įdiegti privačiai"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Įdiegiama: „<xliff:g id="NAME">%1$s</xliff:g>“; baigta: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Atsisiunčiama programa „<xliff:g id="NAME">%1$s</xliff:g>“, <xliff:g id="PROGRESS">%2$s</xliff:g> baigta"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Laukiama, kol bus įdiegta programa „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"„<xliff:g id="NAME">%1$s</xliff:g>“ suarchyvuota. Palieskite, kad atsisiųstumėte."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Būtina atnaujinti programą"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Šios piktogramos programa neatnaujinta. Galite patys atnaujinti, kad iš naujo įgalintumėte šį spartųjį klavišą, arba pašalinkite piktogramą."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Atnaujinti"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Sumažinti aukštį"</string>
     <string name="widget_resized" msgid="9130327887929620">"Valdiklio dydis pakeistas: plotis – <xliff:g id="NUMBER_0">%1$s</xliff:g>, aukštis – <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Spartieji klavišai"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Spartieji klavišai ir pranešimai"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Atsisakyti"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Uždaryti"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Pranešimo atsisakyta"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Asmeninės"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Darbo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Darbo profilis"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruoti"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privati erdvė"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Palieskite, kad nustatytumėte arba atidarytumėte"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privatus"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Užrakinti"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Privačios erdvės perkėlimas"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Programų diegimas"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Įdiegti programas privačioje erdvėje"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Perpildymas"</string>
 </resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 5edee25..c9c4dfa 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Saglabāt lietotņu pāri"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Šis lietotņu pāris netiek atbalstīts šajā ierīcē"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Atveriet ierīci, lai izmantotu šo lietotņu pāri"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Lietotņu pāris nav pieejams"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Lai pārvietotu logrīku, pieskarieties un turiet."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Lai pārvietotu logrīku, uz tā veiciet dubultskārienu un turiet. Varat arī veikt pielāgotas darbības."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plats un %2$d augsts"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Logrīks <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Logrīks <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d plats un %3$d augsts"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pieskarieties logrīkam un turiet to, lai to pārvietotu pa sākuma ekrānu."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pievienot sākuma ekrānam"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Logrīks “<xliff:g id="WIDGET_NAME">%1$s</xliff:g>” ir pievienots sākuma ekrānam"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ieteikumi"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Produktivitātei"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Ziņas un žurnāli"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jūsu atpūtas stūrītis"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Izklaide"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sociālie tīkli"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Veselība un fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Laikapstākļi"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Ieteikumi jums"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Pa labi logrīki <xliff:g id="SELECTED_HEADER">%1$s</xliff:g>, pa kreisi meklēšana un iespējas"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# logrīks}zero{# logrīku}one{# logrīks}other{# logrīki}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# saīsne}zero{# saīšņu}one{# saīsne}other{# saīsnes}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Darba"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Sarunas"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Piezīmju pierakstīšana"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Pievienot"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pievienot logrīku <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Ērta piekļuve noderīgai informācijai"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Lai iegūtu informāciju, neatverot lietotnes, varat pievienot sākuma ekrānam logrīkus"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Pieskarieties, lai mainītu logrīka iestatījumus."</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Noņemt"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Par lietotni"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalēt privāti"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
@@ -108,7 +124,7 @@
     <string name="allow_rotation_title" msgid="7222049633713050106">"Atļaut sākuma ekrāna pagriešanu"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Pagriežot tālruni"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Paziņojumu punkti"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Ieslēgts"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Ieslēgti"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Izslēgts"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Nepieciešama piekļuve paziņojumiem"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei <xliff:g id="NAME">%1$s</xliff:g>."</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Notiek lietotnes “<xliff:g id="NAME">%1$s</xliff:g>” instalēšana. Norise: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Lietotnes <xliff:g id="NAME">%1$s</xliff:g> lejupielāde (<xliff:g id="PROGRESS">%2$s</xliff:g> pabeigti)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Notiek <xliff:g id="NAME">%1$s</xliff:g> instalēšana"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Lietotne <xliff:g id="NAME">%1$s</xliff:g> ir arhivēta. Pieskarieties, lai lejupielādētu."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Lietotne ir jāatjaunina"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Šai ikonai paredzētā lietotne nav atjaunināta. Varat to atjaunināt manuāli, lai atkārtoti iespējotu šo saīsni, vai noņemt ikonu."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Atjaunināt"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Samazināt augstumu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Logrīka lielums mainīts — platums: <xliff:g id="NUMBER_0">%1$s</xliff:g>, augstums: <xliff:g id="NUMBER_1">%2$s</xliff:g>."</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Saīsnes"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Saīsnes un paziņojumi"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Nerādīt"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Aizvērt"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Paziņojums netiek rādīts"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personīgās lietotnes"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Darba lietotnes"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Darba profils"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrs"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privātā telpa"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Pieskarieties, lai iestatītu vai atvērtu"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privātā mape"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloķēšana"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pāriet uz privāto mapi"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Lietotņu instalēšana"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalējiet lietotnes privātajā telpā."</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Pārpilde"</string>
 </resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index a95b7bf..a429c7a 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Зачувај го парот апликации"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Паров апликации не е поддржан на уредов"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Отворете го уредот за да го користите паров апликации"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Парот апликации не е достапен"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Допрете и задржете за да преместите виџет."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Допрете двапати и задржете за да преместите виџет или користете приспособени дејства."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d широк на %2$d висок"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, ширина од %2$d со висина од %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Допрете го и задржете го виџетот за да го движите наоколу на почетниот екран"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетниот екран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g> е додаден на почетниот екран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Неопходни"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Вести и списанија"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Вашата зона за релаксација"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Друштвени"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здравје и фитнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Време"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Препорачано за вас"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> виџети оддесно, „Пребарување“ и „Опции“ одлево"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}other{# виџети}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# кратенка}one{# кратенка}other{# кратенки}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Работни"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Разговори"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Фаќање белешки"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додај го виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Корисни информации на дофат на прстите"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"За да добивате информации без да ги отворате апликациите, може да додадете виџети на почетниот екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Допрете за да ги промените поставките за виџетот"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Отстрани"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. во приватен"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апликација"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Се презема <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> завршено"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека да се инсталира"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> е архивирана. Допрете за преземање."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Потребно е ажурирање на апликацијата"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Апликацијата за оваа икона не е ажурирана. Може да ажурирате рачно за да повторно се овозможи кратенкава или отстранете ја иконата."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намали висина"</string>
     <string name="widget_resized" msgid="9130327887929620">"Големината на виџетот е променета на ширина <xliff:g id="NUMBER_0">%1$s</xliff:g> висина <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Кратенки"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Кратенки и известувања"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Отфрли"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Затвори"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Известувањето е отфрлено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лично"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"За работа"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Работен профил"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Приватен"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Допрете за да поставите или отворите"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Приватен простор"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Заклучи"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Префрлање на „Приватен простор“"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликации"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталирање апликации во „Приватен простор“"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Проширено балонче"</string>
 </resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 1cdcb09..e3b6e6b 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ആപ്പ് ജോടി സംരക്ഷിക്കുക"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ഈ ഉപകരണത്തിൽ ഈ ആപ്പ് ജോടിക്ക് പിന്തുണയില്ല"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ഈ ആപ്പ് ജോടി ഉപയോഗിക്കാൻ ഉപകരണം അൺഫോൾഡ് ചെയ്യുക"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ആപ്പ് ജോടി ലഭ്യമല്ല"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"വിജറ്റ് നീക്കാൻ സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"വിജറ്റ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യൂ, ഹോൾഡ് ചെയ്യൂ അല്ലെങ്കിൽ ഇഷ്‌ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കൂ."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ്"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ്, %2$d വീതി %3$d ഉയരം"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ഹോം സ്‌ക്രീനിന് ചുറ്റും വിജറ്റ് നീക്കാൻ അതിൽ സ്‌പർശിച്ച് പിടിക്കുക"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ഹോം സ്‌ക്രീനിലേക്ക് ചേർക്കുക"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ഹോം സ്‌ക്രീനിലേക്ക് ചേർത്തു"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"നിർദ്ദേശങ്ങൾ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ആവശ്യമായവ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"വാർത്തകളും മാസികകളും"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"നിങ്ങൾക്ക് സുഖപ്രദമായ സ്ഥലം"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"വിനോദം"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"സാമൂഹികം"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ആരോഗ്യവും ശാരീരികക്ഷമതയും"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"കാലാവസ്ഥ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"നിങ്ങൾക്കായി നിർദ്ദേശിച്ചവ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"വലതുവശത്ത് <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> വിജറ്റുകളും ഇടതുവശത്ത് തിരയൽ, ഓപ്ഷനുകൾ എന്നിവയും"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# വിജറ്റ്}other{# വിജറ്റുകൾ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# കുറുക്കുവഴി}other{# കുറുക്കുവഴികൾ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ജോലി"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"സംഭാഷണങ്ങൾ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"കുറിപ്പ് രേഖപ്പെടുത്തൽ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ചേർക്കുക"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ചേർക്കുക"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ഉപകാരപ്രദമായ വിവരങ്ങൾ നിങ്ങളുടെ വിരൽത്തുമ്പിൽ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ആപ്പുകൾ തുറക്കാതെ വിവരങ്ങൾ ലഭിക്കാൻ, നിങ്ങൾക്ക് ഹോം സ്ക്രീനിലേക്ക് വിജറ്റുകൾ ചേർക്കാം"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"വിജറ്റ് ക്രമീകരണം മാറ്റാൻ ടാപ്പ് ചെയ്യുക"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"നീക്കംചെയ്യുക"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാൾ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"സ്വകാര്യമായി ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്‌റ്റാൾ ചെയ്യുക"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കരുത്"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ഇൻസ്‌റ്റാൾ ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ഡൗൺലോഡ് ചെയ്യുന്നു, <xliff:g id="PROGRESS">%2$s</xliff:g> പൂർത്തിയായി"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"ഇൻസ്റ്റാൾ ചെയ്യാൻ <xliff:g id="NAME">%1$s</xliff:g> കാക്കുന്നു"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ആർക്കൈവ് ചെയ്തു. ഡൗൺലോഡ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ആപ്പ് അപ്‌ഡേറ്റ് ചെയ്യേണ്ടതുണ്ട്"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ഈ ഐക്കണിനുള്ള ആപ്പ് അപ്‌ഡേറ്റ് ചെയ്തിട്ടില്ല. ഈ കുറുക്കുവഴി വീണ്ടും പ്രവർത്തനക്ഷമമാക്കാൻ നിങ്ങൾക്ക് നേരിട്ട് അപ്‌ഡേറ്റ് ചെയ്യാം അല്ലെങ്കിൽ ഐക്കൺ നീക്കം ചെയ്യാം."</string>
     <string name="dialog_update" msgid="2178028071796141234">"അപ്ഡേറ്റ് ചെയ്യുക"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ഉയരം കുറയ്‌ക്കുക"</string>
     <string name="widget_resized" msgid="9130327887929620">"വീതി <xliff:g id="NUMBER_0">%1$s</xliff:g> ഉയരം <xliff:g id="NUMBER_1">%2$s</xliff:g>-ലേക്ക് വിഡ്‌ജെറ്റിന്റെ വലുപ്പം മാറ്റി"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"കുറുക്കുവഴികൾ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"കുറുക്കുവഴികളും അറിയിപ്പുകളും"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"നിരസിക്കുക"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"അടയ്ക്കൂ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"അറിയിപ്പ് നിരസിച്ചു"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"വ്യക്തിപരം"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Work"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ഫിൽട്ടർ ചെയ്യുക"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"പരാജയപ്പെട്ടു: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"സ്വകാര്യ സ്പേസ്"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"സജ്ജീകരിക്കാനോ തുറക്കാനോ ടാപ്പ് ചെയ്യുക"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"സ്വകാര്യം"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്‌പേസ് ക്രമീകരണം"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്‌പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ലോക്ക് ചെയ്യുക"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"പ്രൈവറ്റ് സ്‌പേസ് ട്രാൻസിഷനിംഗ്"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"സ്വകാര്യ സ്പേസിലേക്ക് ആപ്പുകൾ ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ഓവർഫ്ലോ"</string>
 </resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 2d53dea..ffc6509 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Апп хослуулалтыг хадгалах"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Энэ апп хослуулалтыг уг төхөөрөмж дээр дэмждэггүй"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Энэ апп хослуулалтыг ашиглахын тулд төхөөрөмжийг дэлгэнэ үү"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Апп хослуулалт боломжгүй байна"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетийг зөөх бол хүрээд, удаан дарна уу."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетийг зөөх эсвэл захиалгат үйлдлийг ашиглахын тулд хоёр товшоод, удаан дарна уу."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d өргөн %2$d өндөр"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> жижиг хэрэгсэл"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджет, %3$d-н өндрийг харьцах нь %2$d-н өргөн"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Виджетийг үндсэн нүүрний эргэн тойронд зөөхийн тулд түүнд хүрээд, удаан дарна уу"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Үндсэн нүүрэнд нэмэх"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг үндсэн нүүрэнд нэмсэн"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Зөвлөмжүүд"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Зайлшгүй хэрэгтэй"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Мэдээ, сэтгүүлүүд"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Таны амралтын бүс"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Энтертэйнмент"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Сошиал"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Эрүүл мэнд, фитнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Цаг агаар"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Танд санал болгосон"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Баруун талд <xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-н виджет, зүүн талд хайлт болон сонгуултууд байна"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# товчлол}other{# товчлол}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Ажил"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Харилцан яриа"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Тэмдэглэл хөтлөх"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Нэмэх"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг нэмэх"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Хэрэгтэй мэдээллээ хурууныхаа үзүүрээр аваарай"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Аппуудыг нээлгүйгээр мэдээлэл авахын тулд та үндсэн нүүрэндээ виджетүүд нэмэх боломжтой"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Жижиг хэрэгслийн тохиргоог өөрчлөхийн тулд товшино уу"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Арилгах"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Устгах"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Аппын мэдээлэл"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Хувийнхад суулгах"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>-г суулгаж байна. <xliff:g id="PROGRESS">%2$s</xliff:g> дууссан"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>-г татаж байна, <xliff:g id="PROGRESS">%2$s</xliff:g> татсан"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> нь суулгахыг хүлээж байна"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g>-г архивласан. Татахын тулд товшино уу."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Аппын шинэчлэлт шаардлагатай"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Энэ дүрс тэмдгийн аппыг шинэчлээгүй. Та энэ товчлолыг дахин идэвхжүүлэх эсвэл дүрсийг хасахын тулд гараар шинэчлэх боломжтой."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Шинэчлэх"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Намсгах"</string>
     <string name="widget_resized" msgid="9130327887929620">"Виджэтийн өргөн <xliff:g id="NUMBER_0">%1$s</xliff:g>, өндөр <xliff:g id="NUMBER_1">%2$s</xliff:g> болсон"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Товчлол"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Товчлол болон мэдэгдэл"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Хаах"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Хаах"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Мэдэгдлийг хаасан"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Хувийн"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Ажил"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ажлын профайл"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Шүүлтүүр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Амжилтгүй болсон: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Хувийн орон зай"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Тохируулах эсвэл нээхийн тулд товших"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Хувийн"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Түгжээ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space-н шилжилт"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Аппуудыг суулгах"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Хувийн орон зайд аппууд суулгана уу"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Урт цэс"</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 9e44733..c8af44e 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ॲपची जोडी सेव्ह करा"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"या ॲपची जोडीला या डिव्हाइसवर सपोर्ट नाही"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ही ॲपची जोडी वापरण्यासाठी डिव्हाइस अनफोल्ड करा"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ॲपची जोडी उपलब्ध नाही"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"विजेट हलवण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"विजेट हलवण्यासाठी किंवा कस्टम कृती वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट, %2$d रुंदी आणि %3$d उंची"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"होम स्क्रीनवर हलवण्यासाठी विजेटला स्पर्श करून धरून ठेवा"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रीनवर जोडा"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> हे विजेट तुमच्या होम स्क्रीनवर जोडले आहे"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"सूचना"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"आवश्यक गोष्टी"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"बातम्‍या आणि मासिके"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"तुमचा आरामदायक झोन"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"आरोग्य आणि फिटनेस"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"हवामान"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"तुमच्यासाठी सुचवलेले"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"उजवीकडे <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> विजेट, डावीकडे शोध आणि पर्याय"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}other{# शॉर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ऑफिस"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"संभाषणे"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"टिपा घेणे"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"जोडा"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट जोडा"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"तुमच्यासाठी सहज उपलब्ध असलेली माहिती"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ॲप्स न उघडता माहिती मिळवण्यासाठी, तुम्ही तुमच्या होम स्क्रीनवर विजेट जोडू शकता"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट सेटिंग्ज बदलण्यासाठी टॅप करा"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"काढा"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करा"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"अ‍ॅप माहिती"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"खाजगीत इंस्टॉल करा"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
@@ -107,7 +123,7 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन फिरवण्‍याची अनुमती द्या"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरवला जातो तेव्हा"</string>
-    <string name="notification_dots_title" msgid="9062440428204120317">"सूचना बिंदू"</string>
+    <string name="notification_dots_title" msgid="9062440428204120317">"नोटिफिकेशन डॉट"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"सुरू"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"बंद"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनांच्या अ‍ॅक्सेसची आवश्यकता आहे"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करत आहे, <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड होत आहे , <xliff:g id="PROGRESS">%2$s</xliff:g> पूर्ण झाले"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> इंस्टॉल करण्याची प्रतिक्षा करत आहे"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> संग्रहित केले आहे. डाउनलोड करण्यासाठी टॅप करा."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"अ‍ॅप अपडेट करणे आवश्‍यक आहे"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"या आयकनसाठी अ‍ॅप अपडेट केलेले नाही. हा शॉटकर्ट पुन्हा सुरू करण्यासाठी तुम्ही मॅन्युअली अपडेट करू शकता किंवा आयकन काढून टाका."</string>
     <string name="dialog_update" msgid="2178028071796141234">"अपडेट करा"</string>
@@ -134,8 +151,8 @@
     <string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीनवर जोडा"</string>
     <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
-    <string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
-    <string name="undo" msgid="4151576204245173321">"पूर्ववत करा"</string>
+    <string name="item_removed" msgid="851119963877842327">"आयटम काढून टाकला"</string>
+    <string name="undo" msgid="4151576204245173321">"पहिल्यासारखे करा"</string>
     <string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
     <string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g> मधील <xliff:g id="NUMBER_0">%1$s</xliff:g> पंक्ती <xliff:g id="NUMBER_1">%2$s</xliff:g> स्तंभ यावर हलवा"</string>
     <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"उंची कमी करा"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेटचा आकार रुंदी <xliff:g id="NUMBER_0">%1$s</xliff:g> उंची <xliff:g id="NUMBER_1">%2$s</xliff:g> मध्ये बदलला"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"शॉर्टकट"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"शॉर्टकट आणि सूचना"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"डिसमिस करा"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"बंद करा"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"सूचना डिसमिस केली"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"वैयक्तिक"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"कार्य"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"खाजगी स्पेस"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"सेट करण्यासाठी किंवा उघडण्यासाठी टॅप करा"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"खाजगी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"लॉक"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"खाजगी स्पेस वर स्विच करणे"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"अ‍ॅप्स इंस्टॉल करा"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"अ‍ॅप्स खाजगी स्पेस मध्ये इंस्टॉल करा"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओव्हरफ्लो"</string>
 </resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index c90082a..68a9238 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Simpan gandingan apl"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Gandingan apl ini tidak disokong pada peranti ini"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Buka lipatan peranti untuk menggunakan gandingan apl ini"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Gandingan apl tidak tersedia"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh &amp; tahan untuk menggerakkan widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketik dua kali &amp; tahan untuk menggerakkan widget atau menggunakan tindakan tersuai."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Lebar %1$d kali tinggi %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, lebar %2$d kali tinggi %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh &amp; tahan widget untuk menggerakkan widget di sekitar skrin utama"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan pada skrin utama"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan pada skrin utama"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Cadangan"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Apl Asas"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Berita &amp; majalah"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zon Santai Anda"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hiburan"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosial"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kesihatan &amp; kecergasan"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Cuaca"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Dicadangkan untuk anda"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> pada sebelah kanan, carian dan pilihan pada sebelah kiri"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Tempat kerja"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Perbualan"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pengambilan nota"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Tambah"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Tambahkan widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Maklumat berguna di hujung jari anda"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Untuk mendapatkan maklumat tanpa membuka apl, anda boleh menambahkan widget pada skrin utama anda"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Ketik untuk menukar tetapan widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alih keluar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam peribadi"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> dipasang, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> memuat turun, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu untuk dipasang"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> diarkibkan. Ketik untuk muat turun."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Kemas kini apl diperlukan"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Apl untuk ikon ini tidak dikemas kini. Anda boleh mengemas kini secara manual untuk mendayakan semula pintasan atau mengalih keluar ikon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Kemas kini"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Kurangkan ketinggian"</string>
     <string name="widget_resized" msgid="9130327887929620">"Saiz widget diubah menjadi <xliff:g id="NUMBER_0">%1$s</xliff:g> lebar <xliff:g id="NUMBER_1">%2$s</xliff:g> tinggi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Pintasan"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Pintasan dan pemberitahuan"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ketepikan"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Tutup"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Pemberitahuan diketepikan"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Peribadi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kerja"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil kerja"</string>
@@ -173,10 +188,14 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nyahjeda"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Tapis"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Ruang peribadi"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Ketik untuk menyediakan atau membuka"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Peribadi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Kunci"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Peralihan Ruang Peribadi"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Pasang apl"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Pasang apl pada Ruang Peribadi"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Limpahan"</string>
 </resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index d1bef97..aca6d7d 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ဤအက်ပ်တွဲချိတ်ခြင်းကို ဤစက်တွင် ပံ့ပိုးမထားပါ"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ဤအက်ပ်တွဲချိတ်ခြင်းကို သုံးရန် စက်ကိုဖြန့်ပါ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"အက်ပ်တွဲချိတ်ခြင်းကို မရနိုင်ပါ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ဝိဂျက်ကို ရွှေ့ရန် တို့ပြီး ဖိထားပါ။"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ဝိဂျက်ကို ရွှေ့ရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"အလျား %1$d နှင့် အမြင့် %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ပင်မစာမျက်နှာတွင်ရွှေ့ရန် ဝိဂျက်ကို တို့ထိ၍ ဖိထားပါ"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်၊ အကျယ် %2$d နှင့် အမြင့် %3$d"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ဝိဂျက်ကို တို့ထိ၍ ဖိထားပြီး ပင်မစာမျက်နှာပေါ်တွင် နေရာအမျိုးမျိုးသို့ ရွှေ့နိုင်သည်"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ကို ပင်မစာမျက်နှာတွင် ထည့်လိုက်ပြီ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"အကြံပြုချက်"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"မရှိမဖြစ်များ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"သတင်းနှင့် မဂ္ဂဇင်း"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"သင်အနားယူသောနေရာ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ဖျော်ဖြေရေး"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"လူမှုရေး"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ကျန်းမာကြံ့ခိုင်ရေး"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"မိုးလေဝသ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"သင့်အတွက် အကြံပြုထားသည်များ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ဝိဂျက်များသည် ညာဘက်တွင်ရှိပြီး ရှာဖွေမှုနှင့် ရွေးစရာများသည် ဘယ်ဘက်တွင်ရှိသည်"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ဝိဂျက် # ခု}other{ဝိဂျက် # ခု}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု}other{ဖြတ်လမ်းလင့်ခ် # ခု}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>၊ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"အလုပ်"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"စကားဝိုင်းများ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"မှတ်စုလိုက်ခြင်း"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ထည့်ရန်"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ထည့်ရန်"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"အသုံးဝင်သော အချက်အလက်များကို အလွယ်တကူ ရယူလိုက်ပါ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"အက်ပ်မဖွင့်ဘဲ အချက်အလက်များရယူရန် ပင်မစာမျက်နှာတွင် ဝိဂျက်များ ထည့်နိုင်သည်"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ဝိဂျက် ဆက်တင်များကို ပြောင်းရန် တို့ပါ"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ဖယ်ရှားမည်"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ရှားရန်"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"အက်ပ်အချက်အလက်"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"သီးသန့်တွင် ထည့်သွင်းရန်"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ကို ထည့်သွင်းနေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ဒေါင်းလုဒ်လုပ်နေသည်၊ <xliff:g id="PROGRESS">%2$s</xliff:g> ပြီးပါပြီ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ကိုထည့်သွင်းရန်စောင့်နေသည်"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ကို သိမ်းထားသည်။ ဒေါင်းလုဒ်လုပ်ရန် တို့ပါ။"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"အက်ပ်ကို အပ်ဒိတ်လုပ်ရန် လိုအပ်သည်"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ဤသင်္ကေတအတွက် အက်ပ်ကို အပ်ဒိတ်လုပ်မထားပါ။ ဤဖြတ်လမ်းလင့်ခ်ကို ပြန်ဖွင့်ရန် ကိုယ်တိုင်အပ်ဒိတ်လုပ်နိုင်သည် (သို့) သင်္ကေတကို ဖယ်ရှားနိုင်သည်။"</string>
     <string name="dialog_update" msgid="2178028071796141234">"အပ်ဒိတ်လုပ်ရန်"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"အမြင့်အား လျှော့ပါ"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget အား အကျယ် <xliff:g id="NUMBER_0">%1$s</xliff:g> အမြင့် <xliff:g id="NUMBER_1">%2$s</xliff:g> အရွယ်အစားပြန်လည်ချိန်ညှိပြီး၏"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ဖြတ်လမ်းများ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ဖြတ်လမ်းလင့်ခ်နှင့် အကြောင်းကြားချက်များ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ပယ်ရန်"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ပိတ်ရန်"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"အသိပေးချက်ကို ဖယ်ထုတ်ပြီးပါပြီ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ကိုယ်ပိုင်"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"အလုပ်"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"အလုပ်ပရိုဖိုင်"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"စစ်ထုတ်ရန်"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"မအောင်မြင်ပါ− <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"သီးသန့်ချတ်ခန်း"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"စနစ်ထည့်သွင်းရန် (သို့) ဖွင့်ရန် တို့ပါ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"သီးသန့်"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"လော့ခ်ချခြင်း"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"သီးသန့်ချတ်ခန်း အပြောင်းအလဲ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"အက်ပ်ထည့်ခြင်း"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"‘သီးသန့်နေရာ’ တွင် အက်ပ်များ ထည့်သွင်းနိုင်သည်"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"မီနူးအပို"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index cd2fb1f..3f82cb3 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Lagre apptilkoblingen"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Åpne enheten for å bruke denne apptilkoblingen"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Apptilkoblingen er ikke tilgjengelig"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Trykk og hold for å flytte en modul."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dobbelttrykk og hold inne for å flytte en modul eller bruke tilpassede handlinger."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bredde x %2$d høyde"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modul"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen, %2$d bred og %3$d høy"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Trykk og hold på modulen for å bevege den rundt på startskjermen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Legg til på startskjermen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen er lagt til på startskjermen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Anbefalt"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter og tidsskrifter"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Avslappingssonen din"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underholdning"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosialt"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kropp og helse"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Været"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Foreslått for deg"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> moduler til høyre, søk og alternativer til venstre"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# moduler}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snarvei}other{# snarveier}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Jobb"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Samtaler"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notatskriving"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Legg til"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Legg til <xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Lett tilgjengelig nyttig informasjon"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"For å se informasjon uten å åpne apper kan du legge til moduler på startskjermen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trykk for å endre modulinnstillinger"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Fjern"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstaller"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer privat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installerer, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Laster ned <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> er fullført"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Venter på å installere <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> er arkivert. Trykk for å laste den ned."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Appen må oppdateres"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Appen for dette ikonet er ikke oppdatert. Du kan oppdatere manuelt for å aktivere denne snarveien igjen, eller du kan fjerne ikonet."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Oppdater"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Reduser høyden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Størrelsen på modulen er endret til bredde <xliff:g id="NUMBER_0">%1$s</xliff:g> og høyde <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Snarveier"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Snarveier og varsler"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Avvis"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Lukk"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Varselet ble avvist"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personlig"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Jobb"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Trykk for å konfigurere eller åpne"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Private Space-overgang"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installer apper"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apper i privat område"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflyt"</string>
 </resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index b9397a0..8e06879 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"एपको पेयर सेभ गर्नुहोस्"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"यस डिभाइसमा यो एप पेयर प्रयोग गर्न मिल्दैन"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"यो एप पेयर प्रयोग गर्न डिभाइस अनफोल्ड गर्नुहोस्"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"एप पेयर उपलब्ध छैन"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"कुनै विजेट सार्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"कुनै विजेट सार्न वा आफ्नो रोजाइका कारबाही प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौडाइ गुणा %2$d उचाइ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट, %2$d चौडाइ र %3$d उचाइ"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"विजेटलाई होम स्क्रिनमा यताउता सार्न त्यसमा टच एन्ड होल्ड गर्नुहोस्"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रिनमा राख्नुहोस्"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"होम स्क्रिनमा <xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हालियो"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"सुझावहरू"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"अत्यावश्यक कुराहरू"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"समाचार तथा पत्रपत्रिकाहरू"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"तपाईंको Chill Zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरञ्जन"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोसल मिडिया"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"स्वास्थ्य तथा तन्दुरुस्ती"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"मौसम"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"तपाईंका लागि सिफारिस गरिएका"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"दायाँ भागमा <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> विजेटहरू, बायाँ भागमा खोज र विकल्पहरू"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# वटा विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# सर्टकट}other{# वटा सर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"कामसम्बन्धी"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"वार्तालापहरू"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"नोट लेख्ने कार्य"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"हाल्नुहोस्"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हाल्नुहोस्"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"उपयोगी जानकारी सजिलै प्राप्त गर्नुहोस्"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"एपहरू नखोलिकनै जानकारी प्राप्त गर्न तपाईं आफ्नो होम स्क्रिनमा विजेटहरू हाल्न सक्नुहुन्छ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेटका सेटिङ बदल्न ट्याप गर्नुहोस्"</string>
@@ -69,24 +84,25 @@
     <string name="hotseat_out_of_space" msgid="7448809638125333693">"मन पर्ने ट्रे अब कुनै ठाँउ छैन"</string>
     <string name="all_apps_button_label" msgid="8130441508702294465">"एपको सूची"</string>
     <string name="all_apps_search_results" msgid="5889367432531296759">"खोज परिणामहरू"</string>
-    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत अनुप्रयोगहरूको सूची"</string>
-    <string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी अनुप्रयोगहरूको सूची"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"व्यक्तिगत एपहरूको सूची"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"कार्यसम्बन्धी एपहरूको सूची"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"हटाउनुहोस्"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइन्स्टल गर्नुहोस्"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"एपसम्बन्धी जानकारी"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी प्रोफाइलमा इन्स्टल गर्नुहोस्"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगरियोस्"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
     <string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
     <string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
-    <string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रिनका सेटिङ र सर्टकटहरू रिड गरियोस्"</string>
+    <string name="permlab_read_settings" msgid="5136500343007704955">"होम स्क्रिनका सेटिङ र सर्टकटहरू रिड गर्नुहोस्"</string>
     <string name="permdesc_read_settings" msgid="4208061150510996676">"एपलाई होम स्क्रिनबाट सेटिङ र सर्टकटहरू रिड गर्ने अनुमति दिन्छ।"</string>
-    <string name="permlab_write_settings" msgid="4820028712156303762">"होम स्क्रिनका सेटिङ र सर्टकटहरू राइट गरियोस्"</string>
+    <string name="permlab_write_settings" msgid="4820028712156303762">"होम स्क्रिनका सेटिङ र सर्टकटहरू राइट गर्नुहोस्"</string>
     <string name="permdesc_write_settings" msgid="726859348127868466">"एपलाई होम स्क्रिनबाट सेटिङ र सर्टकट बदल्ने अनुमति दिन्छ"</string>
     <string name="gadget_error_text" msgid="740356548025791839">"विजेट लोड गर्न सकिएन"</string>
     <string name="gadget_setup_text" msgid="8348374825537681407">"विजेटका सेटिङ"</string>
     <string name="gadget_complete_setup_text" msgid="309040266978007925">"सेटअप पूरा गर्न ट्याप गर्नुहोस्"</string>
-    <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो प्रणाली एप हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string>
+    <string name="uninstall_system_app_text" msgid="4172046090762920660">"यो सिस्टम एप हो र यसलाई स्थापना रद्द गर्न सकिँदैन।"</string>
     <string name="folder_hint_text" msgid="5174843001373488816">"नाम सम्पादन गर्नुहोस्"</string>
     <string name="disabled_app_label" msgid="6673129024321402780">"असक्षम पारिएको <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} सँग सम्बन्धित # सूचना छ}other{{app_name} सँग सम्बन्धित # वटा सूचना छन्}}"</string>
@@ -107,15 +123,15 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"तपाईँको प्रशासकद्वारा असक्षम गरिएको"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रिन रोटेट हुन दिइयोस्"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फोन घुमाउँदा"</string>
-    <string name="notification_dots_title" msgid="9062440428204120317">"सूचनाको प्रतीक जनाउने थोप्लाहरू"</string>
+    <string name="notification_dots_title" msgid="9062440428204120317">"नोटिफिकेसन डट"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"सक्रिय"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"निष्क्रिय"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनासम्बन्धी पहुँच आवश्यक हुन्छ"</string>
-    <string name="msg_missing_notification_access" msgid="281113995110910548">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउन <xliff:g id="NAME">%1$s</xliff:g> को एपसम्बन्धी सूचनाहरूलाई अन गर्नुहोस्"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"नोटिफिकेसन डट देखाउन <xliff:g id="NAME">%1$s</xliff:g> को एपसम्बन्धी सूचनाहरूलाई अन गर्नुहोस्"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"सेटिङहरू बदल्नुहोस्"</string>
-    <string name="notification_dots_service_title" msgid="4284221181793592871">"सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउनुहोस्"</string>
+    <string name="notification_dots_service_title" msgid="4284221181793592871">"नोटिफिकेसन डट देखाउनुहोस्"</string>
     <string name="developer_options_title" msgid="700788437593726194">"विकासकर्ताका लागि उपलब्ध विकल्पहरू"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"एपका आइकनहरू होम स्क्रिनमा राखियोस्"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"एपका आइकनहरू होम स्क्रिनमा राख्नुहोस्"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नयाँ एपका लागि"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"अज्ञात"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"हटाउनुहोस्"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> इन्स्टल गरिँदै छ, <xliff:g id="PROGRESS">%2$s</xliff:g> पूरा भयो"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> डाउनलोड गर्दै, <xliff:g id="PROGRESS">%2$s</xliff:g> सम्पन्‍न"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> स्थापना गर्न प्रतीक्षा गर्दै"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> अभिलेखमा राखिएको छ। डाउनलोड गर्न ट्याप गर्नुहोस्।"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"एप अपडेट गरिनु पर्छ"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"यो आइकनले जनाउने एप अपडेट गरिएको छैन। तपाईं यो सर्टकट फेरि अन गर्न म्यानुअल रूपमा अपडेट गर्न सक्नुहुन्छ वा आइकन नै हटाउनुहोस्।"</string>
     <string name="dialog_update" msgid="2178028071796141234">"अपडेट गर्नुहोस्"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"उँचाइ घटाउनुहोस्"</string>
     <string name="widget_resized" msgid="9130327887929620">"विजेट चौडाइ <xliff:g id="NUMBER_0">%1$s</xliff:g> उचाइ <xliff:g id="NUMBER_1">%2$s</xliff:g> मा पुनः आकार मिलाइयो"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"सर्टकटहरू"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"सर्टकट तथा सूचनाहरू"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"खारेज गर्नुहोस्"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"बन्द गर्नुहोस्"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"सूचना खारेज गरियो"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"व्यक्तिगत"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"कामसम्बन्धी"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"कार्य प्रोफाइल"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"निजी स्पेस"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"सेटअप गर्न वा खोल्न ट्याप गर्नुहोस्"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"लक गर्नुहोस्"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"निजी स्पेस ट्रान्जिसन गरिँदै छ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"एपहरू इन्स्टल गर्नुहोस्"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"निजी स्पेसमा एपहरू इन्स्टल गर्नुहोस्"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओभरफ्लो"</string>
 </resources>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index e462ae0..d23f4d1 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -46,6 +46,10 @@
         @android:color/system_neutral2_200</color>
     <color name="widget_picker_collapse_handle_color_dark">
         @android:color/system_neutral2_700</color>
+    <color name="widget_picker_add_button_background_color_dark">
+        @android:color/system_accent1_200</color>
+    <color name="widget_picker_add_button_text_color_dark">
+        @android:color/system_accent1_800</color>
 
     <color name="work_fab_bg_color">
         @android:color/system_accent1_200</color>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index d41eb7e..613c2e9 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -22,4 +22,10 @@
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
         <item name="android:windowTranslucentStatus">true</item>
     </style>
+
+    <style name="WidgetPickerActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+        <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_dark</item>
+    </style>
 </resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 84d5c15..3da759f 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"App-paar opslaan"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dit app-paar wordt niet ondersteund op dit apparaat"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vouw het apparaat open om dit app-paar te gebruiken"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-paar is niet beschikbaar"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tik en houd vast om een widget te verplaatsen."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en houd vast om een widget te verplaatsen of aangepaste acties te gebruiken."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tik op de widget en houd vast om deze te verplaatsen op het startscherm"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d breed bij %3$d hoog"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Houd je vinger op de widget om deze te verplaatsen op het startscherm"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Toevoegen aan startscherm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toegevoegd aan startscherm"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggesties"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nieuws en tijdschriften"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Je chillzone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sociaal"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Gezondheid en fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weer"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Voorgesteld voor jou"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-widgets aan de rechterkant, zoeken en opties aan de linkerkant"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snelkoppeling}other{# snelkoppelingen}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Werk"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Gesprekken"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Aantekeningen maken"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Toevoegen"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toevoegen"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Nuttige informatie binnen handbereik"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Als je informatie wilt krijgen zonder apps te openen, kun je widgets toevoegen aan je startscherm"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tik om de widgetinstellingen te wijzigen"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwijderen"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleren"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"App-info"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privé installeren"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Vastzetvoorspelling"</string>
@@ -115,7 +131,7 @@
     <string name="title_change_settings" msgid="1376365968844349552">"Instellingen wijzigen"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"Toon meldingsstipjes"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Ontwikkelaarsopties"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"App-iconen toevoegen aan startscherm"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"App-iconen op startscherm"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Voor nieuwe apps"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"Onbekend"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"Verwijderen"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeren, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> wordt gedownload, <xliff:g id="PROGRESS">%2$s</xliff:g> voltooid"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> wacht op installatie"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> is gearchiveerd Tik om te downloaden."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"App-update vereist"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"De app voor dit icoon is niet geüpdatet. Je kunt handmatig updaten om deze snelkoppeling weer aan te zetten of het icoon verwijderen."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Updaten"</string>
@@ -154,16 +171,14 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Hoogte verkleinen"</string>
     <string name="widget_resized" msgid="9130327887929620">"Formaat van widget gewijzigd in breedte <xliff:g id="NUMBER_0">%1$s</xliff:g> en hoogte <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Snelkoppelingen"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Snelkoppelingen en meldingen"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Sluiten"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Sluiten"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Melding gesloten"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privé"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Werk"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Werkprofiel"</string>
     <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Werk-apps hebben badges en zijn zichtbaar voor je IT-beheerder"</string>
     <string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
-    <string name="work_apps_paused_title" msgid="3040901117349444598">"Werk-apps zijn onderbroken"</string>
+    <string name="work_apps_paused_title" msgid="3040901117349444598">"Werk-apps zijn gepauzeerd"</string>
     <string name="work_apps_paused_info_body" msgid="1687828929959237477">"Je krijgt geen meldingen van je werk-apps"</string>
     <string name="work_apps_paused_body" msgid="261634750995824906">"Je werk-apps kunnen je geen meldingen sturen, je batterij niet gebruiken en geen toegang krijgen tot je locatie"</string>
     <string name="work_apps_paused_telephony_unavailable_body" msgid="8358872357502756790">"Je krijgt geen telefoongesprekken, tekstberichten of meldingen van je werk-apps"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filteren"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privéruimte"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tik om in te stellen of te openen"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Vergrendelen"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Overschakelen naar privéruimte"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Apps installeren"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps installeren in privégedeelte"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overloop"</string>
 </resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 3fa8754..d83a02b 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ଏହି ଆପ ପେୟାର ଏ ଡିଭାଇସରେ ସମର୍ଥିତ ନୁହେଁ"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ଏହି ଆପ ପେୟାରକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରନ୍ତୁ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ଆପ ପେୟାର ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ଓସାର ଓ %2$d ଉଚ୍ଚ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ୍"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ, %2$d ଓସାର %3$d ଉଚ୍ଚ"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ହୋମ ସ୍କ୍ରିନର ଆଖପାଖରେ ୱିଜେଟକୁ ମୁଭ କରିବା ପାଇଁ ଏହାକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ହୋମ ସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ର ୱିଜେଟ ହୋମ ସ୍କ୍ରିନରେ ଯୋଡ଼ାଗଲା"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ପରାମର୍ଶଗୁଡ଼ିକ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ଅତ୍ୟାବଶ୍ୟକୀୟ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମାଗାଜିନ"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ଆପଣଙ୍କ ଚିଲ ଜୋନ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ମନୋରଞ୍ଜନ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ସୋସିଆଲ"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ସ୍ୱାସ୍ଥ୍ୟ ଓ ଫିଟନେସ"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"ପାଣିପାଗ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ଆପଣଙ୍କ ପାଇଁ ପ୍ରସ୍ତାବିତ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ଡାହାଣରେ <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ୱିଜେଟଗୁଡ଼ିକ ଅଛି, ବାମରେ ସର୍ଚ୍ଚ ଓ ବିକଳ୍ପଗୁଡ଼ିକ ଅଛି"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ୱିଜେଟ}other{# ୱିଜେଟ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#ଟି ସର୍ଟକଟ୍}other{#ଟି ସର୍ଟକଟ୍}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ୱାର୍କ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ନୋଟ-ଟେକିଂ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ଯୋଗ କରନ୍ତୁ"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ଉପଯୋଗୀ ସୂଚନା ଆପଣଙ୍କ ପାଖରେ ସହଜରେ ଉପଲବ୍ଧ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ଆପ୍ସକୁ ନଖୋଲି ସୂଚନା ପାଇବା ପାଇଁ, ଆପଣ ଆପଣଙ୍କ ହୋମ ସ୍କ୍ରିନରେ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରିପାରିବେ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"କାର୍ଯ୍ୟକାରୀ ଆପ୍‌ ତାଲିକା"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ୍‌ ସୂଚନା"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ ସୂଚନା"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ପ୍ରାଇଭେଟରେ ଇନଷ୍ଟଲ କର"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ ହୋଇଛି"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍‌ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍‌ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g>କୁ ଆର୍କାଇଭ କରାଯାଇଛି। ଡାଉନଲୋଡ୍ କରିବା ପାଇଁ ଟାପ୍‌ କରନ୍ତୁ।"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ଆପକୁ ଅପଡେଟ କରିବା ଆବଶ୍ୟକ"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ଏହି ଆଇକନ ପାଇଁ ଆପକୁ ଅପଡେଟ କରାଯାଇନାହିଁ। ଏହି ସର୍ଟକଟକୁ ପୁଣି-ସକ୍ଷମ କରିବା ପାଇଁ ଆପଣ ମାନୁଆଲୀ ଅପଡେଟ କରିପାରିବେ କିମ୍ବା ଆଇକନଟିକୁ କାଢ଼ି ଦେଇପାରିବେ।"</string>
     <string name="dialog_update" msgid="2178028071796141234">"ଅପଡେଟ କରନ୍ତୁ"</string>
@@ -135,7 +152,7 @@
     <string name="action_move_here" msgid="2170188780612570250">"ଆଇଟମ୍‌କୁ ଏଠାକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ହୋମ ସ୍କ୍ରିନରେ ଆଇଟମ ଯୋଗ କରାଗଲା"</string>
     <string name="item_removed" msgid="851119963877842327">"ଆଇଟମକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
-    <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ୍‍"</string>
+    <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ କରନ୍ତୁ"</string>
     <string name="action_move" msgid="4339390619886385032">"ଆଇଟମ୍‌ ଘୁଞ୍ଚାନ୍ତୁ"</string>
     <string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g>ରେ ଧାଡି <xliff:g id="NUMBER_0">%1$s</xliff:g> ସ୍ତମ୍ଭ <xliff:g id="NUMBER_1">%2$s</xliff:g>କୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ସ୍ଥିତିକୁ ନିଅନ୍ତୁ"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ଉଚ୍ଚତା କମ୍‌ କରନ୍ତୁ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ୱିଜେଟକୁ <xliff:g id="NUMBER_0">%1$s</xliff:g> ଓସାର ଓ <xliff:g id="NUMBER_1">%2$s</xliff:g> ଉଚ୍ଚରେ ପୁନଃଆକାର ଦିଆଗଲା"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ଶର୍ଟକଟ୍‍"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ଶର୍ଟକଟ୍ ଓ ବିଜ୍ଞପ୍ତି"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ଖାରଜ କରନ୍ତୁ"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ବନ୍ଦ କରନ୍ତୁ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ବ୍ୟକ୍ତିଗତ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ୱାର୍କ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ଫିଲ୍ଟର୍"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ସେଟ ଅପ କରିବା କିମ୍ବା ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ପ୍ରାଇଭେଟ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ଲକ କରନ୍ତୁ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ପ୍ରାଇଭେଟ ସ୍ପେସ ଟ୍ରାଞ୍ଜିସନିଂ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ଆପ୍ ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ଆପ୍ସକୁ ପ୍ରାଇଭେଟ ସ୍ପେସରେ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ଓଭରଫ୍ଲୋ"</string>
 </resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 98bc36d..fa01494 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਦਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਨੂੰ ਵਰਤਣ ਲਈ ਡੀਵਾਈਸ ਨੂੰ ਅਣਫੋਲਡ ਕਰੋ"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ਐਪ ਜੋੜਾਬੱਧ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ਕਿਸੇ ਵਿਜੇਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ਵਿਜੇਟ ਲਿਜਾਉਣ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰਕੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ਚੌੜਾਈ ਅਤੇ %2$d ਲੰਬਾਈ"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ, ਇਹ %2$d ਚੌੜਾ ਅਤੇ %3$d ਲੰਬਾ ਹੈ"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ਵਿਜੇਟ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਇੱਧਰ-ਉੱਧਰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰ ਕੇ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"ਸੁਝਾਅ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ਲੋੜੀਂਦੀਆਂ"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ਖਬਰਾਂ ਅਤੇ ਰਸਾਲੇ"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ਤੁਹਾਡੇ ਲਈ ਸਕੂਨਮਈ ਖੇਤਰ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ਮਨੋਰੰਜਨ"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ਸੋਸ਼ਲ"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ਸਿਹਤ ਅਤੇ ਫਿੱਟਨੈੱਸ"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"ਮੌਸਮ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ਤੁਹਾਡੇ ਲਈ ਸੁਝਾਅ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ਵਿਜੇਟ ਸੱਜੇ ਪਾਸੇ ਹਨ, ਖੋਜ ਵਿਜੇਟ ਅਤੇ ਹੋਰ ਵਿਕਲਪ ਖੱਬੇ ਪਾਸੇ ਹਨ"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ਵਿਜੇਟ}one{# ਵਿਜੇਟ}other{# ਵਿਜੇਟ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ਸ਼ਾਰਟਕੱਟ}one{# ਸ਼ਾਰਟਕੱਟ}other{# ਸ਼ਾਰਟਕੱਟ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ਕਾਰਜ-ਸਥਾਨ"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"ਗੱਲਾਂਬਾਤਾਂ"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"ਨੋਟ ਬਣਾਉਣਾ"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"ਸ਼ਾਮਲ ਕਰੋ"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ਮਹੱਤਵਪੂਰਨ ਜਾਣਕਾਰੀ ਤੁਰੰਤ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ਐਪਾਂ ਨੂੰ ਖੋਲ੍ਹੇ ਬਿਨਾਂ ਜਾਣਕਾਰੀ ਪ੍ਰਾਪਤ ਕਰਨ ਲਈ, ਤੁਸੀਂ ਆਪਣੀ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰ ਸਕਦੇ ਹੋ"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ਵਿਜੇਟ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ਹਟਾਓ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ਨਿੱਜੀ ਵਜੋਂ ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਪੂਰਾ ਹੋਇਆ"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, <xliff:g id="PROGRESS">%2$s</xliff:g> ਸੰਪੂਰਣ"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ਸਥਾਪਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ਪੁਰਾਲੇਖਬੱਧ ਹੈ। ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਲੋੜ ਹੈ"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ਇਸ ਪ੍ਰਤੀਕ ਲਈ ਐਪ ਨੂੰ ਅੱਪਡੇਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ। ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਮੁੜ-ਚਾਲੂ ਕਰਨ ਜਾਂ ਪ੍ਰਤੀਕ ਨੂੰ ਹਟਾਉਣ ਲਈ ਤੁਸੀਂ ਹੱਥੀਂ ਅੱਪਡੇਟ ਕਰ ਸਕਦੇ ਹੋ।"</string>
     <string name="dialog_update" msgid="2178028071796141234">"ਅੱਪਡੇਟ ਕਰੋ"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ਉਂਚਾਈ ਘਟਾਓ"</string>
     <string name="widget_resized" msgid="9130327887929620">"ਵਿਜੈਟ ਨੂੰ ਚੌੜਾਈ <xliff:g id="NUMBER_0">%1$s</xliff:g> ਉਂਚਾਈ <xliff:g id="NUMBER_1">%2$s</xliff:g> ਨੂੰ ਮੁੜ ਆਕਾਰ ਦਿੱਤਾ"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ਸ਼ਾਰਟਕੱਟ"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ਸ਼ਾਰਟਕੱਟ ਅਤੇ ਸੂਚਨਾਵਾਂ"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ਖਾਰਜ ਕਰੋ"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ਬੰਦ ਕਰੋ"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ਸੂਚਨਾ ਖਾਰਜ ਕੀਤੀ ਗਈ"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ਨਿੱਜੀ"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"ਕੰਮ ਸੰਬੰਧੀ"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ਫਿਲਟਰ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ਇਹ ਕਾਰਵਾਈ ਅਸਫਲ ਹੋਈ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ਨਿੱਜੀ ਸਪੇਸ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"ਸੈੱਟਅੱਪ ਕਰਨ ਜਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ਲਾਕ ਕਰੋ"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਿੱਚ ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ਓਵਰਫ਼ਲੋ"</string>
 </resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 30a953c..18642d7 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Zapisz parę aplikacji"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta para aplikacji nie jest obsługiwana na tym urządzeniu"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Otwórz urządzenie, aby użyć tej pary aplikacji"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Para aplikacji jest niedostępna"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Naciśnij i przytrzymaj, aby przenieść widżet."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Naciśnij dwukrotnie i przytrzymaj, aby przenieść widżet lub użyć działań niestandardowych."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Szerokość %1$d, wysokość %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d (szerokość), %3$d (wysokość)"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Aby poruszać widżetem po ekranie głównym, kliknij go i przytrzymaj"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Społecznościowe"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdrowie i fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Pogoda"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Proponowane dla Ciebie"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widżety (<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>) po prawej, wyszukiwanie i opcje po lewej"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widżet}few{# widżety}many{# widżetów}other{# widżetu}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# skrót}few{# skróty}many{# skrótów}other{# skrótu}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Służbowe"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Rozmowy"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notatki"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodaj widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Użyteczne informacje w zasięgu ręki"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Możesz dodać widżety do ekranu głównego, aby uzyskiwać informacje bez otwierania aplikacji"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Kliknij, aby zmienić ustawienia widżetu"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Usuń"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikacji"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Zainstaluj prywatnie"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
@@ -113,7 +129,7 @@
     <string name="title_missing_notification_access" msgid="7503287056163941064">"Wymagany jest dostęp do powiadomień"</string>
     <string name="msg_missing_notification_access" msgid="281113995110910548">"Aby pokazywać kropki powiadomień, włącz powiadomienia aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"Zmień ustawienia"</string>
-    <string name="notification_dots_service_title" msgid="4284221181793592871">"Pokaż kropki powiadomień"</string>
+    <string name="notification_dots_service_title" msgid="4284221181793592871">"Pokazuj kropki powiadomień"</string>
     <string name="developer_options_title" msgid="700788437593726194">"Opcje programisty"</string>
     <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Dodawaj ikony aplikacji do ekranu głównego"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"W przypadku nowych aplikacji"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instaluję aplikację <xliff:g id="NAME">%1$s</xliff:g>, postęp: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Pobieranie elementu <xliff:g id="NAME">%1$s</xliff:g>, ukończono: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> oczekuje na instalację"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikacja <xliff:g id="NAME">%1$s</xliff:g> jest zarchiwizowana. Kliknij, aby ją pobrać."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Wymagana aktualizacja aplikacji"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacja z tą ikoną nie jest aktualizowana. Możesz zaktualizować ją ręcznie, aby ponownie uruchomić ten skrót, lub usunąć ikonę."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Aktualizuj"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zmniejsz wysokość"</string>
     <string name="widget_resized" msgid="9130327887929620">"Szerokość i wysokość widżetu zmieniła się na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Skróty"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Skróty i powiadomienia"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Zamknij"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zamknij"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Powiadomienie odrzucone"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobiste"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Służbowe"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil służbowy"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruj"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Obszar prywatny"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Kliknij, aby skonfigurować lub otworzyć"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Prywatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zablokuj"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Przenoszenie obszaru prywatnego"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instaluj aplikacje"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Zainstaluj aplikacje w przestrzeni prywatnej"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozwiń menu"</string>
 </resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index af760f8..6d5c699 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Guardar par de apps"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este par de apps não é suportado neste dispositivo"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abra o dispositivo para usar este par de apps"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"O par de apps não está disponível"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque sem soltar para mover um widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes sem soltar para mover um widget ou utilizar ações personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d de largura por %3$d de altura"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque sem soltar no widget para o mover no ecrã principal"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar ao ecrã principal"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado ao ecrã principal"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essenciais"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Notícias e revistas"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"A sua zona de relaxamento"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociais"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteorologia"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugestões para si"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabalho"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicione o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis à sua disposição"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Para obter informações sem abrir apps, pode adicionar widgets ao seu ecrã principal"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para alterar as definições do widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"A instalar <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"A transferir o <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"A aguardar a instalação do <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"A app <xliff:g id="NAME">%1$s</xliff:g> está arquivada. Toque para transferir."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Atualização da app necessária"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"A app deste ícone não está atualizada. Pode atualizar manualmente para reativar este atalho ou remover o ícone."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Atualizar"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atalhos"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atalhos e notificações"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorar"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Fechar"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notificação ignorada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocar para configurar ou abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Transição do espaço privado"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instale apps no espaço privado"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu adicional"</string>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4359e9a..c0e4457 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -23,7 +23,7 @@
     <string name="work_folder_name" msgid="3753320833950115786">"Trabalho"</string>
     <string name="activity_not_found" msgid="8071924732094499514">"O app não está instalado."</string>
     <string name="activity_not_available" msgid="7456344436509528827">"O app não está disponível"</string>
-    <string name="safemode_shortcut_error" msgid="9160126848219158407">"App transferido por download desativado no modo de segurança"</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"App baixado desativado no modo de segurança"</string>
     <string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no modo de segurança"</string>
     <string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
     <string name="home_screen" msgid="5629429142036709174">"Início"</string>
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Salvar par de apps"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este Par de apps não está disponível no dispositivo"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abra o dispositivo para usar este Par de apps"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"O Par de apps não está disponível"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque e pressione para mover um widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes e mantenha a tela pressionada para mover um widget ou usar ações personalizadas."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>: %2$d de largura por %3$d de altura"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque no widget e o pressione para definir a posição dele na tela inicial"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar à tela inicial"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado à tela inicial"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essenciais"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Notícias e revistas"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sua zona de relaxamento"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimento"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e bem-estar"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugestões para você"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets da <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}one{# atalho}other{# atalhos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabalho"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversas"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Anotações"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Adicionar"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adicionar o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informações úteis ao seu alcance"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Para acessar informações sem precisar abrir os apps, adicione widgets à sua tela inicial"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Toque para mudar as configurações do widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Remover"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informações do app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em particular"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Fazendo download de <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aguardando instalação de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"O app <xliff:g id="NAME">%1$s</xliff:g> está arquivado. Toque para baixar."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Atualização obrigatória do app"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"O app desse ícone não está atualizado. Você pode remover o ícone ou atualizar o app manualmente para reativar esse atalho."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Atualizar"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Diminuir altura"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget redimensionado para a largura <xliff:g id="NUMBER_0">%1$s</xliff:g>, altura <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Atalhos"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Atalhos e notificações"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Dispensar"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Fechar"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notificação dispensada"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Pessoais"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabalho"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabalho"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espaço particular"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Bloquear"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Espaço particular em transição"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalar apps"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar apps no espaço privado"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Balão flutuante"</string>
 </resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 836ac99..0cfaad4 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Salvează perechea de aplicații"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Perechea de aplicații nu este acceptată pe acest dispozitiv"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Deschide dispozitivul ca să folosești această pereche de aplicații"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Perechea de aplicații nu este disponibilă"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Atinge și ține apăsat pentru a muta un widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Atinge de două ori și ține apăsat pentru a muta un widget sau folosește acțiuni personalizate."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lățime și %2$d înălțime"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d lățime x %3$d înălțime"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Atinge lung widgetul pentru a-l muta pe ecranul de pornire"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adaugă pe ecranul de pornire"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a fost adăugat pe ecranul de pornire"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestii"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Esențiale"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Știri și reviste"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de relaxare"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertisment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Rețele sociale"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sănătate și fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerate pentru tine"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgeturi pentru <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> în dreapta, căutare și opțiuni în stânga"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}few{# widgeturi}other{# de widgeturi}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# comandă rapidă}few{# comenzi rapide}other{# de comenzi rapide}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g> <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Serviciu"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Conversații"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Luare de notițe"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Adaugă"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Adaugă widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informații utile la îndemâna ta"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Pentru a primi informații fără să deschizi aplicațiile, poți adăuga widgeturi pe ecranul de pornire"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Atinge ca să schimbi setările pentru widgeturi"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Elimină"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalează"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Informații despre aplicații"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalează în privat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalează"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalează, <xliff:g id="PROGRESS">%2$s</xliff:g> finalizat"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se descarcă (finalizat <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> așteaptă instalarea"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> s-a arhivat. Atinge pentru a descărca."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Este necesară actualizarea aplicației"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplicația pentru această pictogramă nu este actualizată. Poți să actualizezi manual ca să reactivezi comanda rapidă sau să elimini pictograma."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Actualizează"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Redu înălțimea"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetul a fost redimensionat la lățimea <xliff:g id="NUMBER_0">%1$s</xliff:g> și înălțimea <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Comenzi rapide"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Comenzi rapide și notificări"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Închide"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Închide"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Notificare închisă"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Profesionale"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil de serviciu"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtru"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Spațiu privat"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Atinge pentru a configura sau a deschide"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Blochează"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Tranziție pentru spațiul privat"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalează aplicații"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalează aplicații în Spațiul privat"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Suplimentar"</string>
 </resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index bb7b0a0..c0f3baa 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Главный экран"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Сохранить настройки одновременного использования двух приложений"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Сохранить приложения"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Одновременно использовать эти два приложения на устройстве нельзя."</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Чтобы одновременно использовать эти два приложения, разложите устройство."</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Одновременное использование двух приложений недоступно"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Чтобы переместить виджет, нажмите на него и удерживайте"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Чтобы использовать специальные действия или перенести виджет, нажмите на него дважды и удерживайте."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d, высота %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\", ширина: %2$d, высота: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Нажмите на виджет и удерживайте его, чтобы переместить в нужное место на главном экране."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Добавить на главный экран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" добавлен на главный экран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Подсказки"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основное"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и журналы"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Развлечение и общение"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Общение"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здоровье и спорт"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Погода"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Рекомендации"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Виджеты приложения \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" находятся справа, а панель поиска и настройки – слева"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}one{# виджет}few{# виджета}many{# виджетов}other{# виджета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыка}many{# ярлыков}other{# ярлыка}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Рабочие виджеты"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Разговоры"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Создание заметок"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Добавить"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Добавить виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Вся нужная информация перед глазами"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Чтобы не открывать приложения каждый раз, когда нужна информация, добавьте виджеты на главный экран."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Нажмите, чтобы изменить настройки виджета"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Убрать"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Приватная установка"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Установка приложения \"<xliff:g id="NAME">%1$s</xliff:g>\" (выполнено <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Скачивается \"<xliff:g id="NAME">%1$s</xliff:g>\" (<xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Ожидание установки \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Приложение \"<xliff:g id="NAME">%1$s</xliff:g>\" находится в архиве. Нажмите, чтобы скачать"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Обновите приложение"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Эта версия приложения устарела. Обновите его вручную, чтобы снова пользоваться ярлыком, или удалите значок."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Обновить"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Уменьшить высоту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Изменен размер виджета: до <xliff:g id="NUMBER_0">%1$s</xliff:g> в ширину и <xliff:g id="NUMBER_1">%2$s</xliff:g> в высоту"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлыки"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлыки и уведомления"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Закрыть"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Закрыть"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Уведомление закрыто"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Личные"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Рабочие"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Рабочий профиль"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фильтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
     <string name="private_space_label" msgid="2359721649407947001">"Личное пространство"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Нажмите, чтобы настроить или открыть"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Блокировка"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Переход к личному пространству"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Установить приложения"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Установить приложения в личном пространстве"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дополнительное меню"</string>
 </resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 401e0fb..89594c5 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"යෙදුම් යුගල සුරකින්න"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"මෙම යෙදුම් යුගලය මෙම උපාංගයෙහි සහාය නොදක්වයි"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"මෙම යෙදුම් යුගලය භාවිතා කිරීමට උපාංගය දිගහරින්න"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"යෙදුම් යුගලයක් නොමැත"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"විජට් එකක් ගෙන යාමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"විජට් එකක් ගෙන යාමට හෝ අභිරුචි ක්‍රියා භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"පළල %1$d උස %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව, %2$d පළල සහ උස %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"විජට් එක මුල් පිටු තිරය වටා ගෙන යාමට විජට් එක ස්පර්ශ කර අල්ලාගෙන සිටින්න"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"මුල් තිරය වෙත එක් කරන්න"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව මුල් පිටු තිරය වෙත එක් කරන ලදි"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"යෝජනා"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"අත්‍යවශ්‍යාංග"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"පුවත් සහ සඟරා"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ඔබේ නිවුණු කලාපය"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"විනෝදාස්වාදය"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"සමාජයීය"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"සෞඛ්‍යය සහ යෝග්‍යතාව"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"කාලගුණ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"ඔබ සඳහා යෝජිත"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"දකුණේ <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> විජට්, වමේ සෙවීම සහ විකල්ප"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{විජට් #}one{විජට් #}other{විජට් #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{කෙටි මං #}one{කෙටි මං #}other{කෙටි මං #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"කාර්යාලය"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"සංවාද"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"සටහන් කර ගැනීම"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"එක් කරන්න"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව එක් කරන්න"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ප්‍රයෝජනවත් තොරතුරු ඔබගේ ඇඟිලි තුඩු අග"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"යෙදුම් විවෘත නොකර තොරතුරු ලබා ගැනීම සඳහා, ඔබට ඔබගේ මුල් තිරයට විජට් එක් කළ හැකිය"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"විජට් සැකසීම් වෙනස් කිරීමට තට්ටු කරන්න"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ඉවත් කරන්න"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"අස්ථාපනය කරන්න"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"යෙදුම් තොරතුරු"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"පෞද්ගලිකව ස්ථාපනය කරන්න"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> බාගත කරමින්, <xliff:g id="PROGRESS">%2$s</xliff:g> සම්පූර්ණයි"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ස්ථාපනය කිරීමට බලා සිටිමින්"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ලේඛනාරක්ෂණය කර ඇත. බාගැනීමට තට්ටු කරන්න"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"යෙදුම් යාවත්කාලීනයක් අවශ්‍යයි"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"මෙම නිරූපකය සඳහා යෙදුම යාවත්කාලීන කර නැත. ඔබට මෙම කෙටි මඟ යළි සබල කිරීමට හෝ නිරූපකය ඉවත් කිරීමට හස්තීයව යාවත්කාලීන කළ හැකිය."</string>
     <string name="dialog_update" msgid="2178028071796141234">"යාවත්කාලීන කරන්න"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"උස අඩු කරන්න"</string>
     <string name="widget_resized" msgid="9130327887929620">"විජට් පළල <xliff:g id="NUMBER_0">%1$s</xliff:g> උස <xliff:g id="NUMBER_1">%2$s</xliff:g> වෙත ප්‍රමාණකරණය කරන ලදි"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"කෙටිමං"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"කෙටි මං සහ දැනුම්දීම්"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ඉවතලන්න"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"වසන්න"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"දැනුම්දීම ඉවතලන ලදී"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"පුද්ගලික"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"කාර්යාලය"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"කාර්යාල පැතිකඩ"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"පෙරහන"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"අසාර්ථකයි: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"පෞද්ගලික ඉඩ"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"පිහිටුවීමට හෝ විවෘත කිරීමට තට්ටු කරන්න"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"පෞද්ගලික"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"අගුළු දමන්න"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"පෞද්ගලික අවකාශ සංක්‍රමණය"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"යෙදුම් ස්ථාපනය කරන්න"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"පෞද්ගලික අවකාශයට යෙදුම් ස්ථාපනය කරන්න"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"පිටාර යාම"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index fbe64a8..cf87cf8 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Uložiť pár aplikácií"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikácií nie je v tomto zariadení podporovaný"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Ak chcete používať tento pár aplikácií, rozložte zariadenie"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Pár aplikácií nie je k dispozícii"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d na šírku, %3$d na výšku"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pridržaním môžete miniaplikáciu posúvať po ploche"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pridať na plochu"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Na plochu bola pridaná miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Všetko dôležité"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noviny a časopisy"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša komfortná zóna"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sociálne siete"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdravie a kondícia"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Počasie"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Navrhnuté pre vás"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Miniaplikácie <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vpravo, vyhľadávanie a možnosti vľavo"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikácia}few{# miniaplikácie}many{# widgets}other{# miniaplikácií}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Práca"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzácie"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Zapisovanie poznámok"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Pridať"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Pridať miniaplikáciu <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Užitočné informácie poruke"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Ak chcete získavať informácie bez otvárania aplikácií, môžete si na plochu pridať miniaplikácie"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Klepnutím zmeňte nastavenia miniaplikácie"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrániť"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinštalovať"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info o aplikácii"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Inštalovať v súkromí"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Inštaluje sa <xliff:g id="NAME">%1$s</xliff:g>. Dokončené: <xliff:g id="PROGRESS">%2$s</xliff:g>."</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Sťahuje sa aplikácia <xliff:g id="NAME">%1$s</xliff:g>. Stiahnuté: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikácia <xliff:g id="NAME">%1$s</xliff:g> čaká na inštaláciu"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikácia <xliff:g id="NAME">%1$s</xliff:g> je archivovaná. Stiahnite klepnutím."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Vyžaduje sa aktualizácia aplikácie"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikácia, ktorú zastupuje táto ikona, nie je aktualizovaná. Môžete ju ručne aktualizovať, aby odkaz znova fungoval, prípadne môžete ikonu odstrániť."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Aktualizovať"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Znížiť výšku"</string>
     <string name="widget_resized" msgid="9130327887929620">"Veľkosť miniaplikácie bola zmenená na <xliff:g id="NUMBER_0">%1$s</xliff:g> x <xliff:g id="NUMBER_1">%2$s</xliff:g> (šírka x výška)"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Skratky"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Odkazy a upozornenia"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Zavrieť"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zavrieť"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Upozornenie bolo zavreté"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osobné"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Pracovné"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Pracovný profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrujte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Súkromný priestor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Klepnutím nastavte alebo otvorte"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Súkromné"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Uzamknúť"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Prechod súkromného priestoru"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Inštalovať aplikácie"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Inštalácia aplikácií v súkromnom priestore"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozšírená ponuka"</string>
 </resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index d91e83f..7184d7e 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Shrani par aplikacij"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta par aplikacij ni podprt v tej napravi"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Razprite napravo, če želite uporabljati ta par aplikacij"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacij ni na voljo"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržite pripomoček, da ga premaknete."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvakrat se dotaknite pripomočka in ga pridržite, da ga premaknete, ali pa uporabite dejanja po meri."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, višina %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Pripomoček <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«, širina: %2$d, višina: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dotaknite se pripomočka in ga pridržite, če ga želite premikati po začetnem zaslonu."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na začetni zaslon"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>« je dodan na začetni zaslon."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlogi"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnove"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novice in revije"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaš kotiček za sprostitev"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Razvedrilo"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Družbeno"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdravje in fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Vreme"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Predlagano za vas"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Pripomočki <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> na desni, iskanje in možnosti na levi"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# pripomoček}one{# pripomoček}two{# pripomočka}few{# pripomočki}other{# pripomočkov}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# bližnjica}one{# bližnjica}two{# bližnjici}few{# bližnjice}other{# bližnjic}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Služba"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Pogovori"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ustvarjanje zapiskov"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Dodaj"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Dodajanje pripomočka »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>«"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Koristne informacije na dosegu prstov"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Če si želite podatke ogledati brez odpiranja aplikacij, lahko na začetni zaslon dodate pripomočke."</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dotaknite se, če želite spremeniti nastavitve pripomočka."</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Odstrani"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odmesti"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Namesti v zasebno"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj aplikacij"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se namešča, dokončano: <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Prenašanje aplikacije <xliff:g id="NAME">%1$s</xliff:g>; preneseno <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> čaka na namestitev"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Aplikacija <xliff:g id="NAME">%1$s</xliff:g> je arhivirana. Dotaknite se za prenos."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Zahtevana je posodobitev aplikacije"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za to ikono ni posodobljena. Lahko jo ročno posodobite, da znova omogočite to bližnjico, ali pa odstranite ikono."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Posodobi"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zmanjšanje višine"</string>
     <string name="widget_resized" msgid="9130327887929620">"Velikost pripomočka je bila spremenjena na <xliff:g id="NUMBER_0">%1$s</xliff:g> širine in <xliff:g id="NUMBER_1">%2$s</xliff:g> višine"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Bližnjice"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Bližnjice in obvestila"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Opusti"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Zapri"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Obvestilo je bilo opuščeno"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Osebno"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Delo"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Delovni profil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da nastavite ali odprete"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Zasebno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Zaklepanje"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Preklapljanje zasebnega prostora"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Nameščanje aplikacij"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Nameščanje aplikacij v zasebni prostor"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oblaček z dodatnimi elementi"</string>
 </resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index a3bd673..29b3416 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Ruaj çiftin e aplikacioneve"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ky çift aplikacionesh nuk mbështetet në këtë pajisje"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Shpalose pajisjen për të përdorur këtë çift aplikacionesh"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Çifti i aplikacioneve nuk ofrohet"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Prek dhe mbaj shtypur një miniaplikacion për ta zhvendosur."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Trokit dy herë dhe mbaje shtypur një miniapliikacion për ta zhvendosur atë ose për të përdorur veprimet e personalizuara."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i gjerë me %2$d i lartë"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> miniaplikacion"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Miniaplikacioni <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, me gjerësi %2$d dhe lartësi %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Prek dhe mbaj të shtypur miniaplikacionin për ta lëvizur atë nëpër ekranin bazë"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Shto në ekranin bazë"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Miniaplikacioni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> u shtua në ekranin bazë"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugjerime"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Thelbësoret"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Lajme dhe revista"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona jote e qetësisë"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Argëtim"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Rrjetet sociale"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Shëndet dhe fitnes"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Moti"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugjeruar për ty"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Miniaplikacionet e <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> në të djathtë, kërkimi dhe opsionet në të majtë"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikacion}other{# miniaplikacione}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shkurtore}other{# shkurtore}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Puna"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Bisedat"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Mbajtja e shënimeve"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Shto"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Shto miniaplikacionin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Informacione të dobishme në majë të gishtave të tu"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Për të marrë informacione pa i hapur aplikacionet, mund të shtosh miniaplikacione në ekranin bazë"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Trokit për të ndryshuar cilësimet e miniaplikacionit"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Hiqe"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info mbi aplikacionin"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalo në private"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> po instalohet, <xliff:g id="PROGRESS">%2$s</xliff:g> i përfunduar"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> po shkarkohet, <xliff:g id="PROGRESS">%2$s</xliff:g> të përfunduara"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> po pret të instalohet"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> është arkivuar. Trokit për të shkarkuar."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Kërkohet përditësimi i aplikacionit"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacioni për këtë ikonë nuk është përditësuar. Mund ta përditësosh manualisht për të riaktivizuar këtë shkurtore ose hiq ikonën."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Përditëso"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Zvogëlo lartësinë"</string>
     <string name="widget_resized" msgid="9130327887929620">"Madhësia e miniaplikacionit u ndryshua me gjerësinë <xliff:g id="NUMBER_0">%1$s</xliff:g> dhe lartësinë <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Shkurtoret"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Shkurtoret dhe njoftimet"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Hiqe"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Mbyll"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Njoftimi u hoq"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personale"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Punë"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profili i punës"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Hapësira private"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Trokit për të konfiguruar ose për të hapur"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Kyç"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Kalimi te \"Hapësira private\""</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Instalo aplikacionet"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalo aplikacionet në hapësirën private"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Tejkalimi"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 5242848..9535dc0 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Сачувај пар апликација"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Овај пар апликација није подржан на овом уређају"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Отворите уређај да бисте користили овај пар апликација"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Пар апликација није доступан"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ширина од %1$d и висина од %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виџет"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виџет, ширина %2$d и висина %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Додирните и задржите виџет да бисте га померали по почетном екрану"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Неопходне апликације"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и часописи"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Друштвене мреже"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здравље и фитнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Време"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Предложено за вас"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Виџети <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> са десне стране, претрага и опције са леве стране"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}few{# виџета}other{# виџета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Посао"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Конверзације"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Прављење бележака"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Додај"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додајте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Корисне информације надохват руке"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Да бисте пронашли информације без отварања апликација, можете да додате виџете на почетни екран"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
@@ -73,7 +88,8 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Листа пословних апликација"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Уклони"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Инфор. о апликацији"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Подаци о апликацији"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инсталирај на приватни"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> готово"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Апликација <xliff:g id="NAME">%1$s</xliff:g> је архивирана. Додирните да бисте је преузели."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Треба да ажурирате апликацију"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Апликација за ову икону није ажурирана. Можете да је ручно ажурирате да бисте поново омогућили ову пречицу или уклоните икону."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Смањи висину"</string>
     <string name="widget_resized" msgid="9130327887929620">"Величина виџета је промењена на ширину <xliff:g id="NUMBER_0">%1$s</xliff:g> и висину <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Пречице"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Пречице и обавештења"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Одбаци"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Затвори"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Обавештење је одбачено"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Лично"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Посао"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Пословни профил"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватни простор"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Додирните да бисте подесили или отворили"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Приватно"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Закључавање"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Пренос приватног простора"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Инсталирајте апликације"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Инсталирај апликације у приватан простор"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Преклопно"</string>
 </resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 1e1436f..a3f5625 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Startskärm"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Spara appar som ska användas tillsammans"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Spara app-par"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vik upp enheten för att använda de här apparna som ska användas tillsammans"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"App-paret är inte tillgängligt"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Tryck länge för att flytta en widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryck snabbt två gånger och håll kvar för att flytta en widget eller använda anpassade åtgärder."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bred gånger %2$d hög"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d i bredd och %3$d i höjd"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tryck länge på widgeten om du vill flytta den på startskärmen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Viktigt"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter och tidskrifter"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Koppla av"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underhållning"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Socialt"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Hälsa och träning"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Väder"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Våra förslag"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgetar för <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> till höger, sökning och alternativ till vänster"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetar}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genväg}other{# genvägar}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbete"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Konversationer"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Anteckna"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Lägg till"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Lägg till widgeten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Användbar information nära till hands"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Om du vill ha information utan att öppna appar kan du lägga till widgetar på startskärmen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Tryck för att ändra inställningarna för widgeten"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ta bort"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installera i privat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
@@ -106,7 +122,7 @@
     <string name="settings_button_text" msgid="8873672322605444408">"Startinställningar"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Inaktiverat av administratören"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"Tillåt rotering av startskärmen"</string>
-    <string name="allow_rotation_desc" msgid="8662546029078692509">"När mobilen vrids"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"När telefonen vrids"</string>
     <string name="notification_dots_title" msgid="9062440428204120317">"Aviseringsprickar"</string>
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"På"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"Av"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> installeras. <xliff:g id="PROGRESS">%2$s</xliff:g> har slutförts"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> laddas ned, <xliff:g id="PROGRESS">%2$s</xliff:g> klart"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> väntar på installation"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> har arkiverats. Tryck för att ladda ned."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Du måste uppdatera appen"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Appen för den här ikonen har inte uppdaterats. Du kan uppdatera den manuellt för att återaktivera genvägen eller ta bort ikonen."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Uppdatera"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Minska höjden"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widgetens storlek har ändrats till: bredd <xliff:g id="NUMBER_0">%1$s</xliff:g>, höjd <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Genvägar"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Genvägar och aviseringar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ignorera"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Stäng"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Aviseringen togs bort"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Privat"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Arbete"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Jobbprofil"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tryck för att ställa in eller öppna"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Lås"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Överföring av privat rum"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Installera appar"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installera appar i privat rum"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Fler alternativ"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 2486cae..8d74b83 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Hifadhi jozi ya programu"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Jozi hii ya programu haitumiki kwenye kifaa hiki"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Fungua kifaa ili utumie jozi hii ya programu"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Kipengele cha jozi ya programu hakipatikani"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Gusa na ushikilie ili usogeze wijeti."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Gusa mara mbili na ushikilie ili usogeze wijeti au utumie vitendo maalum."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Upana wa %1$d na kimo cha %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, upana wa %2$d kwa urefu wa %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Gusa na ushikilie wijeti ili uisogeze kwenye skrini ya kwanza"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Weka kwenye skrini ya kwanza"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Umeongeza wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g> kwenye skrini ya kwanza"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mapendekezo"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Habari na magazeti"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Mahali Pako pa Kupumzika"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Burudani"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Mitandao jamii"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Afya na siha"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Hali ya Hewa"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Unayopendekezewa"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Wijeti za <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ziko upande wa kulia, utafutaji na chaguo ziko upande wa kushoto"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{Wijeti #}other{Wijeti #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{Njia # ya mkato}other{Njia # za mkato}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Kazini"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Mazungumzo"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Kuandika madokezo"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Weka"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Weka wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Maelezo muhimu, popote ulipo"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Ili upate maelezo bila kufungua programu, unaweza kuweka wijeti kwenye skrini yako ya kwanza"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Gusa ili ubadilishe mipangilio ya wijeti"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Ondoa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Maelezo ya programu"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Sakinisha faraghani"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Inasakinisha <xliff:g id="NAME">%1$s</xliff:g>, imekamilika <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> inapakuliwa, <xliff:g id="PROGRESS">%2$s</xliff:g> imekamilika"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> inasubiri kusakinisha"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> imewekwa kwenye kumbukumbu. Gusa ili uipakue."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Unahitaji kusasisha programu"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Programu ya aikoni hii haijasasishwa. Unaweza kusasisha mwenyewe ili uruhusu upya njia hii ya mkato au uondoe aikoni."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Sasisha"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Punguza urefu"</string>
     <string name="widget_resized" msgid="9130327887929620">"Wijeti imepunguzwa hadi upana <xliff:g id="NUMBER_0">%1$s</xliff:g> urefu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Njia za mkato"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Arifa na njia za mkato"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Ondoa"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Funga"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Arifa imeondolewa"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Binafsi"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Kazini"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Wasifu wa kazini"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
-    <string name="ps_container_title" msgid="4391796149519594205">"Ya Faragha"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Gusa ili uweke mipangilio au ufungue"</string>
+    <string name="ps_container_title" msgid="4391796149519594205">"Faragha"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Funga"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Mabadiliko ya Nafasi ya Faragha"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Sakinisha programu"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Sakinisha programu kwenye Sehemu ya Faragha"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menyu ya vipengee vya ziada"</string>
 </resources>
diff --git a/res/values-sw600dp/config.xml b/res/values-sw600dp/config.xml
index e718d9c..bddfcfc 100644
--- a/res/values-sw600dp/config.xml
+++ b/res/values-sw600dp/config.xml
@@ -18,6 +18,9 @@
     <!-- The duration of the PagedView page snap animation -->
     <integer name="config_pageSnapAnimationDuration">550</integer>
 
+    <!-- The duration of the PagedView page snap animation -->
+    <integer name="config_keyboardTaskFocusSnapAnimationDuration">400</integer>
+
     <!-- The duration of the Widget picker opening and closing animation -->
     <integer name="config_bottomSheetOpenDuration">500</integer>
     <integer name="config_bottomSheetCloseDuration">500</integer>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index cc1f09e..eda9b2d 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -40,6 +40,7 @@
 <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
     <dimen name="spring_loaded_hotseat_top_margin">65dp</dimen>
+    <dimen name="min_hotseat_icon_space">17dp</dimen>
 
 <!-- Dragging -->
     <dimen name="drop_target_top_margin">64dp</dimen>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 4d0ac38..dd58cee 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -32,7 +32,4 @@
 <!-- Widget picker-->
     <dimen name="widget_list_horizontal_margin">49dp</dimen>
     <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
-
-<!-- Bottom sheet-->
-    <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 2b0382d..27aba6b 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -37,9 +37,7 @@
 
 <!-- Widget picker-->
     <dimen name="widget_list_horizontal_margin">30dp</dimen>
-
-<!-- Bottom sheet-->
-    <dimen name="bottom_sheet_extra_top_padding">300dp</dimen>
+    <dimen name="widget_cell_horizontal_padding">16dp</dimen>
 
     <!--  Folder spaces  -->
     <dimen name="folder_footer_horiz_padding">24dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index cb0ca67..68f3633 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"இந்தச் சாதனத்தில் இந்த ஆப்ஸ் ஜோடி ஆதரிக்கப்படவில்லை"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"இந்த ஆப்ஸ் ஜோடியைப் பயன்படுத்த சாதனத்தை விரியுங்கள்"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ஆப்ஸ் ஜோடி கிடைக்கவில்லை"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"விட்ஜெட்டை நகர்த்தத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"விட்ஜெட்டை நகர்த்த இருமுறை தட்டிப் பிடிக்கவும் அல்லது பிரத்தியேகச் செயல்களைப் பயன்படுத்தவும்."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d அகலத்திற்கு %2$d உயரம்"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட், %2$d அகலம் மற்றும் %3$d உயரம்"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"முகப்புத் திரையைச் சுற்றி விட்ஜெட்டை நகர்த்த அதைத் தொட்டுப் பிடியுங்கள்"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"முகப்புத் திரையில் சேர்"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட் முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"பரிந்துரைகள்"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"அத்தியாவசியமானவை"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"செய்திகள் &amp; பத்திரிக்கைகள்"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"உங்கள் மனதுக்கு இதமானவை"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"பொழுதுபோக்கு"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"சமூகம்"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ஆரோக்கியம் &amp; உடற்பயிற்சி"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"வானிலை"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"உங்களுக்கான பரிந்துரைகள்"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> விட்ஜெட்கள் வலதுபுறத்தில் உள்ளன, தேடல் மற்றும் விருப்பங்கள் இடதுபுறத்தில் உள்ளன"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# விட்ஜெட்}other{# விட்ஜெட்டுகள்}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ஷார்ட்கட்}other{# ஷார்ட்கட்கள்}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"பணி"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"உரையாடல்கள்"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"குறிப்பெடுத்தல்"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"சேர்"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்டைச் சேர்க்கும்"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"விரல்நுனியில் பயனுள்ள தகவல்களைப் பெறுங்கள்"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"முகப்புத் திரையில் விட்ஜெட்டுகளைச் சேர்த்து ஆப்ஸைத் திறக்காமலேயே தகவல்களைப் பெறலாம்"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"விட்ஜெட் அமைப்புகளை மாற்றத் தட்டவும்"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"அகற்று"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ஆப்ஸ் தகவல்"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"தனிப்பட்டதில் நிறுவு"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்ட ஆப்ஸைப் பின் செய்தல்"</string>
@@ -115,7 +131,7 @@
     <string name="title_change_settings" msgid="1376365968844349552">"அமைப்புகளை மாற்று"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"அறிவிப்புப் புள்ளிகளைக் காட்டு"</string>
     <string name="developer_options_title" msgid="700788437593726194">"டெவெலப்பர் விருப்பங்கள்"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"முகப்புத் திரையில் ஆப்ஸ் ஐகான்களைச் சேர்"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"முகப்புத் திரையில் ஆப்ஸ் ஐகான்களைச் சேர்த்தல்"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"புதிய ஆப்ஸை நிறுவும்போது"</string>
     <string name="package_state_unknown" msgid="7592128424511031410">"தெரியாதது"</string>
     <string name="abandoned_clean_this" msgid="7610119707847920412">"அகற்று"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> நிறுவப்படுகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g>ஐப் பதிவிறக்குகிறது, <xliff:g id="PROGRESS">%2$s</xliff:g> முடிந்தது"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>ஐ நிறுவுவதற்காகக் காத்திருக்கிறது"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> காப்பிடப்பட்டுள்ளது. பதிவிறக்க தட்டுங்கள்."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ஆப்ஸைப் புதுப்பியுங்கள்"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"இந்த ஐகானுக்கான ஆப்ஸ் புதுப்பிக்கப்படவில்லை. இந்த ஷார்ட்கட்டை மீண்டும் இயக்கவோ ஐகானை அகற்றவோ நீங்களாகவே புதுப்பிக்கலாம்."</string>
     <string name="dialog_update" msgid="2178028071796141234">"புதுப்பி"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"உயரத்தைக் குறை"</string>
     <string name="widget_resized" msgid="9130327887929620">"அகலம் <xliff:g id="NUMBER_0">%1$s</xliff:g> மற்றும் உயரம் <xliff:g id="NUMBER_1">%2$s</xliff:g>க்கு விட்ஜெட் அளவு மாற்றப்பட்டது"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ஷார்ட்கட்கள்"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ஷார்ட்கட்கள் மற்றும் அறிவிப்புகள்"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"நிராகரி"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"மூடும் பட்டன்"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"அறிவிப்பு நிராகரிக்கப்பட்டது"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"தனிப்பட்டவை"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"பணி"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"பணிக் கணக்கு"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"வடிப்பான்"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"தோல்வி: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"தனிப்பட்ட சேமிப்பிடம்"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"அமைக்கவோ திறக்கவோ தட்டுங்கள்"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"தனிப்பட்டது"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"பூட்டு"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ஆப்ஸை நிறுவுதல்"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"தனிப்பட்ட சேமிப்பிடத்தில் ஆப்ஸை நிறுவும்"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
 </resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 27cec72..4533fda 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"యాప్ పెయిర్‌ను సేవ్ చేయండి"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ఈ పరికరంలో ఈ యాప్ పెయిర్ సపోర్ట్ చేయదు"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ఈ యాప్ పెయిర్‌ను ఉపయోగించడానికి పరికరాన్ని అన్‌ఫోల్డ్ చేయండి"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"యాప్ పెయిర్ అందుబాటులో లేదు"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"విడ్జెట్‌ను తరలించడానికి తాకి &amp; నొక్కి ఉంచండి."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"విడ్జెట్‌ను తరలించడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కండి &amp; హోల్డ్ చేయి."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d వెడల్పు X %2$d ఎత్తు"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్, %2$d వెడల్పు %3$d ఎత్తు ఉండాలి"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"విడ్జెట్‌ను మొదటి స్క్రీన్‌లో తిప్పడానికి దాన్ని తాకి, &amp; నొక్కి పట్టుకోండి"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"మొదటి స్క్రీన్‌కు జోడించండి"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"మొదటి స్క్రీన్‌కు <xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్ జోడించబడింది"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"సూచనలు"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"నిత్యావసరాలు"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"వార్తలు &amp; మ్యాగజైన్లు"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"మీరు ప్రశాంతంగా ఉండే ప్రదేశం"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"వినోదం"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"సామాజికం"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"ఆరోగ్యం &amp; ఫిట్‌నెస్"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"వాతావరణం"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"మీ కోసం సూచించినవి"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"కుడి వైపున <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> విడ్జెట్‌లు, ఎడమ వైపున సెర్చ్, ఇతర ఆప్షన్‌లు"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# విడ్జెట్}other{# విడ్జెట్‌లు}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# షార్ట్‌కట్}other{# షార్ట్‌కట్‌లు}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"ఆఫీస్"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"సంభాషణలు"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"నోట్-టేకింగ్"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"జోడించండి"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్‌ను జోడించండి"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"మీ చేతివేళ్ల మీద ఉపయోగకరమైన సమాచారం"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"యాప్‌లను తెరవకుండా సమాచారాన్ని పొందడానికి, మీరు మీ మొదటి స్క్రీన్‌కు విడ్జెట్‌లను జోడించవచ్చు"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"విడ్జెట్ సెట్టింగ్‌లను మార్చడానికి ట్యాప్ చేయండి"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"తీసివేయండి"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్‌స్టాల్ చేయండి"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"యాప్ సమాచారం"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ప్రైవేట్ ఇన్‌స్టాల్"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్‌స్టాల్ చేయండి"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g>‌ను ఇన్‌స్టాల్ చేయడం, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> డౌన్‌లోడ్ అవుతోంది, <xliff:g id="PROGRESS">%2$s</xliff:g> పూర్తయింది"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ఇన్‌స్టాల్ కావడానికి వేచి ఉంది"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> ఆర్కైవ్ చేయబడింది. డౌన్‌లోడ్ చేయడానికి ట్యాప్ చేయండి."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"యాప్‌ను అప్‌డేట్ చేయడం అవసరం"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"ఈ చిహ్నం కోసం యాప్ అప్‌డేట్ చేయబడలేదు. మీరు ఈ షార్ట్‌కట్‌ను మళ్లీ ఎనేబుల్ చేయడానికి మాన్యువల్‌గా అప్‌డేట్ చేయవచ్చు లేదా చిహ్నాన్ని తీసివేయవచ్చు."</string>
     <string name="dialog_update" msgid="2178028071796141234">"అప్‌డేట్ చేయండి"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ఎత్తును తగ్గించు"</string>
     <string name="widget_resized" msgid="9130327887929620">"విడ్జెట్ సైజ్‌ వెడల్పు <xliff:g id="NUMBER_0">%1$s</xliff:g>కి, ఎత్తు <xliff:g id="NUMBER_1">%2$s</xliff:g>కి మార్చబడింది"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"షార్ట్‌కట్స్"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"షార్ట్‌కట్‌లు మరియు నోటిఫికేషన్‌లు"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"తీసివేయండి"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"మూసివేస్తుంది"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"నోటిఫికేషన్ తీసివేయబడింది"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"వ్యక్తిగతం"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"వర్క్"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"కార్యాలయ ప్రొఫైల్"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ఫిల్టర్ చేయి"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"విఫలమైంది: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ప్రైవేట్ స్పేస్"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"సెటప్ చేయడానికి లేదా తెరవడానికి ట్యాప్ చేయండి"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ప్రైవేట్"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్‌లు"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్‌ను లాక్/అన్‌లాక్ చేయండి"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"లాక్ చేయండి"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ప్రైవేట్ స్పేస్ కేటాయించడం జరుగుతుంది"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"యాప్‌లను ఇన్‌స్టాల్ చేయండి"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ప్రైవేట్ స్పేస్‌కు యాప్‌లను ఇన్‌స్టాల్ చేయండి"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ఓవర్‌ఫ్లో"</string>
 </resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 78cbcfa..efcd36f 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"บันทึกคู่แอป"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ไม่รองรับคู่แอปนี้ในอุปกรณ์เครื่องนี้"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"กางอุปกรณ์เพื่อใช้คู่แอปนี้"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"การจับคู่อุปกรณ์ไม่พร้อมให้บริการ"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"แตะค้างไว้เพื่อย้ายวิดเจ็ต"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"แตะสองครั้งค้างไว้เพื่อย้ายวิดเจ็ตหรือใช้การดำเนินการที่กำหนดเอง"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"กว้าง %1$d x สูง %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"วิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"วิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, กว้าง %2$d สูง %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"แตะวิดเจ็ตค้างไว้เพื่อย้ายไปรอบๆ หน้าจอหลัก"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"เพิ่มลงในหน้าจอหลัก"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ลงในหน้าจอหลักแล้ว"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"คำแนะนำ"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"รายการที่ห้ามพลาด"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ข่าวสารและนิตยสาร"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"พื้นที่สบายๆ ของคุณ"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ความบันเทิง"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"โซเชียล"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"สุขภาพและการออกกำลังกาย"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"สภาพอากาศ"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"แนะนำให้คุณ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"วิดเจ็ต<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>ทางด้านขวา การค้นหาและตัวเลือกทางด้านซ้าย"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{วิดเจ็ต # รายการ}other{วิดเจ็ต # รายการ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ทางลัด # รายการ}other{ทางลัด # รายการ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"งาน"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"การสนทนา"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"การจดบันทึก"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"เพิ่ม"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"เข้าถึงข้อมูลที่เป็นประโยชน์ได้จากปลายนิ้ว"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"หากต้องการรับข้อมูลโดยไม่เปิดแอป ให้เพิ่มวิดเจ็ตลงในหน้าจอหลัก"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"แตะเพื่อเปลี่ยนการตั้งค่าวิดเจ็ต"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"นำออก"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ข้อมูลแอป"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในส่วนตัว"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
@@ -101,7 +117,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"โฟลเดอร์: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> รายการ"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"โฟลเดอร์: <xliff:g id="NAME">%1$s</xliff:g>, อย่างน้อย <xliff:g id="SIZE">%2$d</xliff:g> รายการ"</string>
     <string name="app_pair_name_format" msgid="8134106404716224054">"คู่แอป: <xliff:g id="APP1">%1$s</xliff:g> และ <xliff:g id="APP2">%2$s</xliff:g>"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"วอลเปเปอร์และรูปแบบ"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"วอลเปเปอร์และสไตล์"</string>
     <string name="edit_home_screen" msgid="8947858375782098427">"แก้ไขหน้าจอหลัก"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"การตั้งค่าหน้าจอหลัก"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ปิดใช้โดยผู้ดูแลระบบ"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"กำลังติดตั้ง <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"กำลังดาวน์โหลด <xliff:g id="NAME">%1$s</xliff:g> เสร็จแล้ว <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> กำลังรอติดตั้ง"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"เก็บถาวร <xliff:g id="NAME">%1$s</xliff:g> แล้ว แตะเพื่อดาวน์โหลด"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ต้องอัปเดตแอป"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"แอปสำหรับไอคอนนี้ยังไม่ได้อัปเดต คุณอัปเดตด้วยตนเองได้โดยเปิดใช้ทางลัดนี้อีกครั้งหรือนำไอคอนออก"</string>
     <string name="dialog_update" msgid="2178028071796141234">"อัปเดต"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"ลดความสูง"</string>
     <string name="widget_resized" msgid="9130327887929620">"ปรับขนาดของวิดเจ็ตเป็นกว้าง <xliff:g id="NUMBER_0">%1$s</xliff:g> สูง <xliff:g id="NUMBER_1">%2$s</xliff:g> แล้ว"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ทางลัด"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"ทางลัดและการแจ้งเตือน"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"ปิด"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"ปิด"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"ปิดการแจ้งเตือนแล้ว"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ส่วนตัว"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"งาน"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"โปรไฟล์งาน"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ตัวกรอง"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ไม่สำเร็จ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"พื้นที่ส่วนตัว"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"แตะเพื่อตั้งค่าหรือเปิด"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"ส่วนตัว"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"ล็อก"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"การเปลี่ยนไปใช้พื้นที่ส่วนตัว"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ติดตั้งแอป"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"ติดตั้งแอปไปยังพื้นที่ส่วนตัว"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"การดำเนินการเพิ่มเติม"</string>
 </resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index acf60ff..27c2dd8 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"Home"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"I-save ang pares ng app"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"I-save ang app pair"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hindi sinusuportahan sa device na ito ang pares ng app na ito"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"I-unfold ang device para magamit ang pares ng app na ito"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Hindi available ang pares ng app"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Pindutin nang matagal para ilipat ang widget."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"I-double tap at pindutin nang matagal para ilipat ang widget o gumamit ng mga custom na pagkilos."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d ang lapad at %3$d ang taas"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pindutin nang matagal ang widget para ilipat-lipat ito sa home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Idagdag sa home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Idinagdag sa home screen ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mga Suhestyon"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Mga essential"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Balita at mga magazine"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ang Iyong Chill Zone"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kalusugan at fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Lagay ng panahon"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Iminumungkahi para sa iyo"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Mga widget ng <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> sa kanan, paghahanap at mga opsyon sa kaliwa"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# na widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}one{# shortcut}other{# na shortcut}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabaho"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Mga Pag-uusap"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Pagtatala"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Idagdag"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Idagdag ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Abot-kamay na mahalagang impormasyon"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Para makakuha ng impormasyon nang hindi nagbubukas ng mga app, puwede kang magdagdag ng mga widget sa iyong home screen"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"I-tap para baguhin ang mga setting ng widget"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Alisin"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"I-uninstall"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pribadong i-install"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi ng app"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Ini-install ang <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> kumpleto"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Dina-download na ang <xliff:g id="NAME">%1$s</xliff:g>, tapos na ang <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Hinihintay nang mag-install ang <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Naka-archive ang <xliff:g id="NAME">%1$s</xliff:g>. I-tap para i-download."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Kinakailangang i-update ang app"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Hindi updated ang app para sa icon na ito. Puwede kang manual na mag-update para ma-enable ulit ang shortcut na ito, o alisin ang icon."</string>
     <string name="dialog_update" msgid="2178028071796141234">"I-update"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Bawasan ang taas"</string>
     <string name="widget_resized" msgid="9130327887929620">"Na-resize ang widget sa lapad <xliff:g id="NUMBER_0">%1$s</xliff:g> taas <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Mga Shortcut"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Mga shortcut at notification"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"I-dismiss"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Isara"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Na-dismiss ang notification"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabaho"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Profile sa trabaho"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Pribadong space"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"I-tap para i-set up o buksan"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Pribado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"I-lock"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Pag-transition ng Pribadong Space"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Mag-install ng mga app"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Mag-install ng mga app sa Pribadong Space"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 1449202..9e723dd 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Uygulama çiftini kaydedin"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu uygulama çifti bu cihazda desteklenmiyor"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bu uygulama çiftini kullanmak için katlanmış durumda olan cihazı açın"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Uygulama çifti kullanılamıyor"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget\'ı taşımak için dokunup basılı tutun."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Widget\'ı taşımak veya özel işlemleri kullanmak için iki kez dokunup basılı tutun."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"genişlik: %1$d, yükseklik: %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı, %2$d genişlik x %3$d yükseklik"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Ana ekranda taşımak için widget\'a dokunup basılı tutun"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Önemliler"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Haberler ve dergiler"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Huzur alanınız"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Eğlence"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosyal"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sağlık ve fitness"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Hava durumu"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sizin için önerilenler"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widget\'ları sağda, arama ve seçenekler solda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kısayol}other{# kısayol}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"İş"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Görüşmeler"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Not alma"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Ekle"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ekle"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Faydalı bilgiler parmaklarınızın ucunda"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Uygulama açmadan bilgi almak için ana ekranınıza widget ekleyebilirsiniz"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Widget ayarlarını değiştirmek için dokunun"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Sil"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükleyin"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulama önerme"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> yükleniyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> indiriliyor, <xliff:g id="PROGRESS">%2$s</xliff:g> tamamlandı"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> uygulaması yüklenmek için bekliyor"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> arşivlendi. İndirmek için dokunun."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Uygulama güncellemesi gerekli"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Bu simgenin uygulaması güncellenmemiş. Simgeyi kaldırabilir ya da uygulamayı manuel olarak güncelleyerek bu kısayolu yeniden etkinleştirebilirsiniz."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Güncelle"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Yüksekliği azalt"</string>
     <string name="widget_resized" msgid="9130327887929620">"Widget, <xliff:g id="NUMBER_0">%1$s</xliff:g> genişlik ve <xliff:g id="NUMBER_1">%2$s</xliff:g> yükseklik değerine yeniden boyutlandırıldı"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Kısayollar"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Kısayollar ve bildirimler"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Kapat"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Kapat"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Bildirim kapatıldı"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Kişisel"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"İş"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"İş profili"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Gizli alan"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Kurmak veya açmak için dokunun"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Gizli"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Kilit"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Gizli Alana Geçiş"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Uygulamaları yükleme"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Uygulamaları özel alana yükleyin"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Taşma"</string>
 </resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index ad325cc..9552a57 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Зберегти пару додатків"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ці два додатки не можна одночасно використовувати на цьому пристрої"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Розкладіть пристрій, щоб одночасно використовувати ці два додатки"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Одночасне використання двох додатків недоступне"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Натисніть і втримуйте, щоб перемістити віджет."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двічі натисніть і втримуйте віджет, щоб перемістити його або виконати інші дії."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина – %1$d, висота – %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Віджет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Віджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\", ширина: %2$d, висота: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Натисніть і втримуйте віджет, щоб перемістити його в потрібне місце на головному екрані"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Додати на головний екран"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Віджет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> додано на головний екран"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Пропозиції"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основне"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новини й журнали"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ваша зона розваг"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Розваги"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Соціальні мережі"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здоров’я і фітнес"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Погода"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Пропозиції для вас"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>: віджети праворуч, пошук і опції ліворуч"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджет}one{# віджет}few{# віджети}many{# віджетів}other{# віджета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлик}one{# ярлик}few{# ярлики}many{# ярликів}other{# ярлика}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Робочі"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Розмови"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Створення нотаток"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Додати"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Додати віджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Корисна інформація завжди під рукою"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Щоб отримувати інформацію, не відкриваючи додатки, ви можете додати на головний екран віджети"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Натисніть, щоб змінити налаштування віджета"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Видалити"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Видалити додаток"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Про додаток"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Установити приватно"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
@@ -101,7 +117,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Папка \"<xliff:g id="NAME">%1$s</xliff:g>\", елементів: <xliff:g id="SIZE">%2$d</xliff:g>"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Папка \"<xliff:g id="NAME">%1$s</xliff:g>\", елементів: <xliff:g id="SIZE">%2$d</xliff:g> або більше"</string>
     <string name="app_pair_name_format" msgid="8134106404716224054">"Одночасне використання двох додатків: <xliff:g id="APP1">%1$s</xliff:g> і <xliff:g id="APP2">%2$s</xliff:g>"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Оформлення і стиль"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Оформлення й стиль"</string>
     <string name="edit_home_screen" msgid="8947858375782098427">"Редагувати головний екран"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Налаштування головного екрана"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Вимкнув адміністратор"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> встановлюється, виконано <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> завантажується, <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> очікує на завантаження"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Додаток <xliff:g id="NAME">%1$s</xliff:g> заархівовано. Натисніть, щоб завантажити."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Потрібно оновити додаток"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Додаток для цього значка не оновлено. Ви можете оновити його вручну, щоб знову ввімкнути цю швидку команду, або можете вилучити значок."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Оновити"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Зменшити висоту"</string>
     <string name="widget_resized" msgid="9130327887929620">"Розміри віджета змінено на <xliff:g id="NUMBER_0">%1$s</xliff:g> завширшки та <xliff:g id="NUMBER_1">%2$s</xliff:g> заввишки"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Ярлики"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Ярлики та сповіщення"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Закрити"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Закрити"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Сповіщення закрито"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Особисті додатки"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Робочі додатки"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Робочий профіль"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Натисніть, щоб налаштувати або відкрити"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Приватні"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Заблокувати"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Перехід у приватний простір"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Установити додатки"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Установити додатки в особистому просторі"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Додаткове меню"</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 1c0e3ae..50334a0 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‏%1$s کے لیے ایپ کی معلومات"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"ایپس کے جوڑے کو محفوظ کریں"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ایپس کا یہ جوڑا اس آلے پر تعاون یافتہ نہیں ہے"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ایپس کے اس جوڑے کا استعمال کرنے کیلئے آلے کو اَن فولڈ کریں"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"ایپ کا جوڑا دستیاب نہیں ہے"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"ویجیٹ منتقل کرنے کے لیے ٹچ کریں اور پکڑ کر رکھیں۔"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"ویجیٹ کو منتقل کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کے لیے دوبار تھپتھپائیں اور پکڑ کر رکھیں۔"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏%1$d چوڑا اور ‎%2$d اونچا"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ، ‏%2$d چوڑا اور ‏%3$d اونچا ہے"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ویجیٹ کو ہوم اسکرین کے چاروں طرف منتقل کرنے کے لیے اسے ٹچ کریں اور دبائے رکھیں"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ہوم اسکرین میں شامل کریں"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ کو ہوم اسکرین میں شامل کیا گیا"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"تجاویز"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"لوازمات"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"خبریں اور میگزینز"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"آپ کا آرام دہ زون"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"تفریح"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"سماجی"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"صحت اور تندرستی"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"موسم"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"آپ کے لیے تجویز کردہ"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> دائیں طرف وجیٹس، بائیں طرف تلاش اور اختیارات"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ویجیٹ}other{# ویجیٹس}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# شارٹ کٹ}other{# شارٹ کٹس}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"دفتری ویجیٹس"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"گفتگوئیں"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"نوٹ لکھنا"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"شامل کریں"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ شامل کریں"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"مفید معلومات کو آسانی سے حاصل کریں"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"ایپس کو کھولے بغیر معلومات حاصل کرنے کے لیے آپ اپنی ہوم اسکرین پر ویجیٹس شامل کر سکتے ہیں"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ویجیٹ ترتیبات تبدیل کرنے کے لیے تھپتھپائیں"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"ہٹائیں"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"اَن انسٹال کریں"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"ایپ کی معلومات"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"پرائیویٹ میں انسٹال کریں"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال کی جا رہی ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گئی"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ڈاؤن لوڈ ہو رہا ہے، <xliff:g id="PROGRESS">%2$s</xliff:g> مکمل ہو گیا"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> انسٹال ہونے کا انتظار کر رہی ہے"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> کو آرکائیو کر لیا گیا ہے۔ ڈاؤن لوڈ کرنے کیلئے تھپتھپائیں۔"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"ایپ کی اپ ڈیٹ درکار ہے"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"اس آئیکن کیلئے ایپ کو اپ ڈیٹ نہیں کیا گیا ہے۔ آپ اس شارٹ کٹ کو دوبارہ فعال کرنے کے لیے دستی طور پر اپ ڈیٹ کر سکتے ہیں، یا آئیکن کو ہٹا سکتے ہیں۔"</string>
     <string name="dialog_update" msgid="2178028071796141234">"اپ ڈیٹ کریں"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"اونچائی کم کریں"</string>
     <string name="widget_resized" msgid="9130327887929620">"ویجیٹ کے سائز کو چوڑائی <xliff:g id="NUMBER_0">%1$s</xliff:g> اونچائی <xliff:g id="NUMBER_1">%2$s</xliff:g> میں تبدیل کر دیا گیا"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"شارٹ کٹس"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"شارٹ کٹس اور اطلاعات"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"برخاست کریں"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"بند کریں"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"اطلاع مسترد ہو گئی"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"ذاتی"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"دفتری"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"دفتری پروفائل"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فلٹر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ناکام ہو گيا: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"نجی اسپیس"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"سیٹ اپ کرنے یا کھولنے کے لیے تھپتھپائیں"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"نجی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"مقفل کریں"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"نجی اسپیس کی منتقلی"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"ایپس انسٹال کریں"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"پرائیویٹ اسپیس میں ایپس انسٹال کریں"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"اوورفلو"</string>
 </resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8e6d392..89ccde3 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Ilova juftini saqlash"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu ilova jufti ushbu qurilmada ishlamaydi"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Bu ilova juftidan foydalanish uchun qurilmani oching"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Ikkita ilovadan bir vaqtda foydalanish mumkin emas"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidjetni bosib turgan holatda suring."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Eni %1$d, bo‘yi %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ta vidjet"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti, eniga: %2$d, boʻyiga: %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Bosh ekranda surish uchun vidjet ustiga bosib turing"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Bosh ekranga chiqarish"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Asosiy ilovalar"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Yangiliklar va jurnallar"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sokin hududingiz"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hordiq"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Ijtimoiy"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salomatlik va sport"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ob-havo"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sizga tavsiya etiladi"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidjetlari oʻngda, qidiruv va sozlamalar chapda"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ta vidjet}other{# ta vidjet}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ta yorliq}other{# ta yorliq}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Ish"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Suhbatlar"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Qayd olish"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Chiqarish"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjetini chiqarish"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Barcha kerakli axborot doim yoningizda"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Kerakli ilovalarni ochmasdan turib ulardan axborot olish uchun vidjetlarni bosh ekranga chiqaring"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Vidjet sozlamalarini oʻzgartirish uchun bosing"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Olib tashlash"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Ilova haqida"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Maxfiy oʻrnatish"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> oʻrnatlmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> yakunlandi"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> yuklab olinmoqda, <xliff:g id="PROGRESS">%2$s</xliff:g> bajarildi"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilovasi o‘rnatilishi kutilmoqda"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> arxivlangan. Yuklab olish uchun bosing."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Ilovani yangilash zarur"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Bu belgi uchun ilova yangilanmagan. Ushbu yorliqni qayta yoqish uchun oddiy usulda yangilashingiz yoki belgini olib tashlashingiz mumkin."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Yangilash"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Bo‘yini kichraytirish"</string>
     <string name="widget_resized" msgid="9130327887929620">"Vidjetning eni <xliff:g id="NUMBER_0">%1$s</xliff:g>, bo‘yi <xliff:g id="NUMBER_1">%2$s</xliff:g> qilib o‘zgartirildi"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Tezkor tugmalar"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Yorliqlar va bildirishnomalar"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Yopish"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Yopish"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Bildirishnoma yopildi"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Shaxsiy"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Ish"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Ish profili"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Saralash"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Sozlash yoki ochish uchun bosing"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Yopiq"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Qulflash"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Maxfiy joyga almashtirish"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Ilovalar oʻrnatish"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Ilovalarni Maxfiy makonga oʻrnatish"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kengaytirish"</string>
 </resources>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 841e07b..fa87221 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -47,8 +47,8 @@
 
     <color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
 
-    <color name="folder_pagination_color_light">@android:color/system_accent1_600</color>
-    <color name="folder_pagination_color_dark">@android:color/system_accent1_200</color>
+    <color name="page_indicator_dot_color_light">@android:color/system_accent1_600</color>
+    <color name="page_indicator_dot_color_dark">@android:color/system_accent1_200</color>
 
     <color name="home_settings_header_accent">@android:color/system_accent1_600</color>
     <color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
@@ -97,12 +97,17 @@
         @android:color/system_neutral2_700</color>
     <color name="widget_picker_collapse_handle_color_light">
         @android:color/system_neutral2_200</color>
+    <color name="widget_picker_add_button_background_color_light">
+        @android:color/system_accent1_600</color>
+    <color name="widget_picker_add_button_text_color_light">
+        @android:color/system_accent1_0</color>
 
     <color name="work_fab_bg_color">
         @android:color/system_accent1_200</color>
     <color name="work_fab_icon_color">
         @android:color/system_accent1_900</color>
 
+    <color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
 
     <color name="material_color_on_secondary_fixed_variant">@android:color/system_accent2_700</color>
     <color name="material_color_on_tertiary_fixed_variant">@android:color/system_accent3_700</color>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8ed3089..448d2a2 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Lưu cặp ứng dụng"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cặp ứng dụng này không hoạt động được trên thiết bị này"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Hãy mở thiết bị để dùng cặp ứng dụng này"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Hiện không có cặp ứng dụng này"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Chạm và giữ để di chuyển một tiện ích."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Nhấn đúp và giữ để di chuyển một tiện ích hoặc sử dụng các thao tác tùy chỉnh."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Rộng %1$d x cao %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, rộng %2$d x cao %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Chạm và giữ tiện ích để di chuyển tiện ích đó xung quanh màn hình chính"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Thêm vào màn hình chính"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Đã thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g> vào màn hình chính"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Nội dung đề xuất"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Các tiện ích thiết yếu"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Tin tức và tạp chí"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Giai điệu thư giãn của bạn"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Giải trí"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Mạng xã hội"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Sức khoẻ và thể chất"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Thời tiết"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Đề xuất cho bạn"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Tiện ích <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ở bên phải, công cụ tìm kiếm và tuỳ chọn ở bên trái"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# tiện ích}other{# tiện ích}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lối tắt}other{# lối tắt}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Công việc"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Cuộc trò chuyện"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ghi chú"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Thêm"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Thông tin hữu ích ngay trong tầm tay bạn"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Để nhận thông tin mà không cần mở các ứng dụng, bạn có thể thêm tiện ích vào màn hình chính"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Nhấn để thay đổi chế độ cài đặt tiện ích"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Xóa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Gỡ cài đặt"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Cài đặt ở chế độ riêng tư"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Không đề xuất ứng dụng"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"Đang cài đặt <xliff:g id="NAME">%1$s</xliff:g>, hoàn tất <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"Đang tải xuống <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> hoàn tất"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"Đang chờ cài đặt <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"Đã lưu trữ <xliff:g id="NAME">%1$s</xliff:g> Nhấn để tải xuống."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Cần cập nhật ứng dụng"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"Ứng dụng cho biểu tượng này chưa được cập nhật. Bạn có thể cập nhật theo cách thủ công để bật lại phím tắt này hoặc xóa biểu tượng."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Cập nhật"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Giảm chiều cao"</string>
     <string name="widget_resized" msgid="9130327887929620">"Đã đổi kích thước tiện ích thành chiều rộng <xliff:g id="NUMBER_0">%1$s</xliff:g> chiều cao <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Lối tắt"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Phím tắt và thông báo"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Loại bỏ"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Đóng"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Đã loại bỏ thông báo"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Cá nhân"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Công việc"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Hồ sơ công việc"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Bộ lọc"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Không gian riêng tư"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Nhấn để thiết lập hoặc mở"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Riêng tư"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Khoá"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Chuyển đổi sang không gian riêng tư"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Cài đặt ứng dụng"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Cài đặt ứng dụng vào Không gian riêng tư"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Bong bóng bổ sung"</string>
 </resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 53b85f2..d675db3 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -29,17 +29,30 @@
     <string name="home_screen" msgid="5629429142036709174">"主屏幕"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"分屏"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"保存应用对"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"保存应用组合"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"在该设备上无法使用此应用对"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"展开设备即可使用此应用组合"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"应用对不可用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住即可移动微件。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动它"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件,宽 %2$d,高 %3$d"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新闻与杂志"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娱乐"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"社交"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"健康与健身"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"天气"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"为您推荐"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"右边是<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>微件,左边是搜索功能和选项"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 个微件}other{# 个微件}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 个快捷方式}other{# 个快捷方式}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>,<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"对话"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"记事"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"添加"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"添加“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"实用信息触手可及"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"要想不打开应用就能获取信息,您可以将相应微件添加到主屏幕"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"点按即可更改微件设置"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"卸载"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"应用信息"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安装到私密个人资料中"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供应用建议"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安装<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下载<xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g>正在等待安装"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"已归档“<xliff:g id="NAME">%1$s</xliff:g>”。点按即可下载。"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"需要更新应用"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"此图标对应的应用未更新。您可以手动更新以重新启用该快捷方式,或者移除此图标。"</string>
     <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"减小高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"微件尺寸已调整为:宽度 <xliff:g id="NUMBER_0">%1$s</xliff:g>,高度 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"快捷方式"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"快捷方式和通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"关闭"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"关闭"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"已关闭通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"个人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作资料"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"过滤器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私密空间"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"点按即可设置或打开"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私密"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"锁定"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"私密空间转换"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"安装应用"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"将应用安装到私密空间"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"菜单"</string>
 </resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e6aaef5..e9c968a 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"此裝置不支援此應用程式配對"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"打開裝置即可使用此應用程式配對"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"應用程式配對無法使用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"輕觸並按住即可移動小工具。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"㩒兩下之後㩒住,就可以郁小工具或者用自訂操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d 闊,%2$d 高"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>小工具,闊 %2$d,高 %3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可移到主畫面的任何位置"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"加去主畫面"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已經將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具加咗去主畫面"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必備之選"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新聞和雜誌"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"放鬆專區"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娛樂"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"社交"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"健康和健身"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"天氣"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"為你推薦"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"右邊係「<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>」小工具,左邊係搜尋功能同選項"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 個小工具}other{# 個小工具}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"對話"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"加<xliff:g id="WIDGET_NAME">%1$s</xliff:g>小工具"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"實用資訊,唾手可得"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增至主畫面,就可以直接查看資料,無需開啟應用程式"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕按即可變更小工具設定"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資料"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載 <xliff:g id="NAME">%1$s</xliff:g>,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝 <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"「<xliff:g id="NAME">%1$s</xliff:g>」已封存。輕按即可下載。"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"必須更新應用程式"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"你尚未更新這個圖示代表的應用程式。你可以手動更新以重新啟用此快速鍵,或者移除圖示。"</string>
     <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"已調整小工具的大小至闊 <xliff:g id="NUMBER_0">%1$s</xliff:g> 高 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"捷徑"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"捷徑同通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"關閉"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"關閉"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"關閉咗通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作設定檔"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"操作失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"輕按即可設定或開啟"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"上鎖"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"轉為「私人空間」"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"將應用程式安裝在「私人空間」中"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"顯示更多"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 462b651..e891ee2 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"這部裝置不支援這組應用程式配對"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"展開裝置即可使用這組應用程式配對"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"這個應用程式配對無法使用"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"按住即可移動小工具。"</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"輕觸兩下並按住即可移動小工具或使用自訂操作。"</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"寬度為 %1$d,高度為 %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可將它移到主畫面上的任何位置"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具 (寬 %2$d,高 %3$d)"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可拖曳到主畫面的任何位置"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"新增至主畫面"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具新增到主畫面"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"常用項目"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新聞與雜誌"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"放鬆專區"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娛樂"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"社群"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"健康與塑身"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"天氣"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"個人化建議"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"右邊是「<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>」小工具,左邊是搜尋功能和選項"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 項小工具}other{# 項小工具}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"工作"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"對話"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"做筆記"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"新增"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"新增「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"實用資訊隨手可得"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"只要將小工具新增到主畫面,就可以直接查看資訊,不必開啟應用程式"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"輕觸即可變更小工具設定"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"移除"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資訊"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"正在安裝「<xliff:g id="NAME">%1$s</xliff:g>」(已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>)"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"正在下載「<xliff:g id="NAME">%1$s</xliff:g>」,已完成 <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"正在等待安裝「<xliff:g id="NAME">%1$s</xliff:g>」"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"已封存「<xliff:g id="NAME">%1$s</xliff:g>」。輕觸即可下載。"</string>
     <string name="dialog_update_title" msgid="114234265740994042">"必須更新應用程式"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"這個圖示代表的應用程式未更新。手動更新即可重新啟用這個捷徑,你也可以移除圖示。"</string>
     <string name="dialog_update" msgid="2178028071796141234">"更新"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"減少高度"</string>
     <string name="widget_resized" msgid="9130327887929620">"已將小工具的寬度和高度分別調整為 <xliff:g id="NUMBER_0">%1$s</xliff:g> 和 <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"捷徑"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"捷徑和通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"關閉"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"關閉"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"已關閉通知"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"個人"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"工作"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"工作資料夾"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"輕觸即可設定或開啟"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"鎖定"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"轉換私人空間狀態"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"安裝應用程式"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"將應用程式安裝在私人空間中"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"溢位"</string>
 </resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index efc0824..7a0871a 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -31,15 +31,28 @@
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
     <string name="save_app_pair" msgid="5647523853662686243">"Londoloza i-app ebhangqiwe"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
+    <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Lokhu kubhanqwa kwe-app akusekelwa kule divayisi"</string>
+    <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vula idivayisi ukuze usebenzise lokhu kubhanqwa kwe-app"</string>
+    <string name="app_pair_not_available" msgid="3556767440808032031">"Ukubhangqwa kwe-app akutholakali"</string>
     <string name="long_press_widget_to_add" msgid="3587712543577675817">"Thinta uphinde ubambe ukuze uhambise iwijethi."</string>
     <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Thepha kabili uphinde ubambe ukuze uhambise iwijethi noma usebenzise izindlela ezingokwezifiso."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ububanzi ngokungu-%2$d ukuya phezulu"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Iwijethi elingu-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>, ububanzi obungu-%2$d ngokuphakama okungu-%3$d"</string>
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Thinta uphinde ubambe iwijethi ukuyihambisa kusikrini sasekhaya"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Faka kusikrini sasekhaya"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g> yengezwe kusikrini sasekhaya"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iziphakamiso"</string>
+    <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Okusemqoka"</string>
+    <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Izindaba nomagazini"</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Indawo Ozipholela Kuyo"</string>
+    <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Okokozijabulisa"</string>
+    <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Okomphakathi"</string>
+    <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Ezempilo nokufaneleka"</string>
+    <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Isimo sezulu"</string>
+    <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Okuphakanyiselwe wena"</string>
+    <string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Amawijethi okuthi <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> kwesokudla, ukusesha nokukhethwayo kwesobunxele"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{iwijethi #}one{amawijethi #}other{amawijethi #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{isinqamuleli #}one{izinqamuleli #}other{izinqamuleli #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -52,6 +65,8 @@
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Umsebenzi"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Izingxoxo"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Ukuthatha amanothi"</string>
+    <string name="widget_add_button_label" msgid="2761267068711937179">"Engeza"</string>
+    <string name="widget_add_button_content_description" msgid="1810530016360039643">"Engeza iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"Ulwazi oluwusizo phambi nje kwakho"</string>
     <string name="widget_education_content" msgid="1731667670753497052">"Ukuze uthole ulwazi ngaphandle kokuvula ama-app, ungakwazi ukwengeza amawijethi kusikrini sakho sasekhaya"</string>
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Thepha ukuze ushintshe amasethingi ewijethi"</string>
@@ -74,6 +89,7 @@
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Susa"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Khipha"</string>
     <string name="app_info_drop_target_label" msgid="692894985365717661">"Ulwazi nge-app"</string>
+    <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Faka ngokugodliwe"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
     <string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
@@ -125,6 +141,7 @@
     <string name="app_installing_title" msgid="5864044122733792085">"I-<xliff:g id="NAME">%1$s</xliff:g> iyafakwa, seyiqede <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
     <string name="app_downloading_title" msgid="8336702962104482644">"I-<xliff:g id="NAME">%1$s</xliff:g> iyalandwa, <xliff:g id="PROGRESS">%2$s</xliff:g> kuqediwe"</string>
     <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ilinde ukufakwa"</string>
+    <string name="app_archived_title" msgid="9124290918876665128">"I-<xliff:g id="NAME">%1$s</xliff:g> ifakwe kungobo yomlando. Thepha ukuze udawunilode."</string>
     <string name="dialog_update_title" msgid="114234265740994042">"Kudingeka isibuyekezo se-app"</string>
     <string name="dialog_update_message" msgid="4176784553982226114">"I-app yalesi sithonjana ibuyekeziwe. Ungabuyekeza mathupha ukuze uphinde unike amandla lesi sinqamuleli, noma ususe isithonjana."</string>
     <string name="dialog_update" msgid="2178028071796141234">"Vuselela"</string>
@@ -154,10 +171,8 @@
     <string name="action_decrease_height" msgid="282377193880900022">"Nciphisa ubude"</string>
     <string name="widget_resized" msgid="9130327887929620">"Iwijethi inikezwe usayizi omusha ngobubanzi obungu-<xliff:g id="NUMBER_0">%1$s</xliff:g> ubude obungu-<xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"Izinqamuleli"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Izinqamuleli nezaziso"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"Cashisa"</string>
     <string name="accessibility_close" msgid="2277148124685870734">"Vala"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Isaziso sicashisiwe"</string>
     <string name="all_apps_personal_tab" msgid="4190252696685155002">"Okomuntu siqu"</string>
     <string name="all_apps_work_tab" msgid="4884822796154055118">"Umsebenzi"</string>
     <string name="work_profile_toggle_label" msgid="3081029915775481146">"Iphrofayela yomsebenzi"</string>
@@ -174,9 +189,13 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Hlunga"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Isikhala esiyimfihlo"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Thepha ukuze usethe noma uvule"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Okuyimfihlo"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
+    <string name="ps_container_lock_title" msgid="2640257399982364682">"Khiya"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"Ukuguqulwa Kwendawo Yangasese"</string>
+    <string name="ps_add_button_label" msgid="8611055839242385935">"Faka ama-app"</string>
+    <string name="ps_add_button_content_description" msgid="3254274107740952556">"Faka ama-app Endaweni Engasese"</string>
     <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ukugcwala kakhulu"</string>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 8d84c90..f23c790 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -42,14 +42,17 @@
     <attr name="overviewScrimColor" format="color" />
     <attr name="popupNotificationDotColor" format="color" />
     <attr name="notificationDotColor" format="color" />
+    <attr name="focusOutlineColor" format="color" />
+    <attr name="focusInnerOutlineColor" format="color" />
 
-    <attr name="folderPaginationColor" format="color" />
+    <attr name="pageIndicatorDotColor" format="color" />
     <attr name="folderPreviewColor" format="color" />
     <attr name="folderBackgroundColor" format="color" />
     <attr name="folderIconRadius" format="float" />
     <attr name="folderIconBorderColor" format="color" />
     <attr name="folderTextColor" format="color" />
     <attr name="folderHintTextColor" format="color" />
+    <attr name="appPairSurfaceInFolder" format="color" />
     <attr name="isFolderDarkText" format="boolean" />
     <attr name="workspaceAccentColor" format="color" />
     <attr name="workspaceSurfaceColor" format="color" />
@@ -71,6 +74,8 @@
     <attr name="widgetPickerSelectedTabTextColor" format="color"/>
     <attr name="widgetPickerUnselectedTabTextColor" format="color"/>
     <attr name="widgetPickerCollapseHandleColor" format="color"/>
+    <attr name="widgetPickerAddButtonBackgroundColor" format="color"/>
+    <attr name="widgetPickerAddButtonTextColor" format="color"/>
 
     <!-- BubbleTextView specific attributes. -->
     <declare-styleable name="BubbleTextView">
@@ -189,23 +194,16 @@
          defaults to 2 * numAllAppsColumns -->
         <attr name="numExtendedAllAppsColumns" format="integer" />
 
+        <!-- Number of rows to calculate the cell height for all apps when it's necessary.
+          Defaults to numRows. Requires FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE to be enabled. -->
+        <attr name="numAllAppsRowsForCellHeightCalculation" format="integer" />
+
         <!-- numHotseatIcons defaults to numColumns, if not specified -->
         <attr name="numHotseatIcons" format="integer" />
         <!-- Number of icons to use when extending the hotseat size,
          defaults to 2 * numHotseatIcons -->
         <attr name="numExtendedHotseatIcons" format="integer" />
 
-        <!-- alignment of hotseat to the grid.
-        Not applicable for 3 button mode when taskbar is enabled -->
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpan" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelLandscape" format="integer" />
-        <!-- defaults to numColumns, if not specified -->
-        <attr name="hotseatColumnSpanTwoPanelPortrait" format="integer" />
-
         <!-- Spacing to have at the end of the nav buttons in large screen 3 button nav,
              defaults to @dimen/taskbar_button_margin_default -->
         <attr name="inlineNavButtonsEndSpacing" format="reference" />
@@ -219,26 +217,32 @@
         <!-- File that contains the specs for the workspace.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="workspaceSpecsId" format="reference" />
+        <!-- defaults to workspaceSpecsId, if not specified -->
         <attr name="workspaceSpecsTwoPanelId" format="reference" />
         <!-- File that contains the specs for all apps.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="allAppsSpecsId" format="reference" />
+        <!-- defaults to allAppsSpecsId, if not specified -->
         <attr name="allAppsSpecsTwoPanelId" format="reference" />
         <!-- File that contains the specs for the workspace.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="folderSpecsId" format="reference" />
+        <!-- defaults to folderSpecsId, if not specified -->
         <attr name="folderSpecsTwoPanelId" format="reference" />
         <!-- File that contains the specs for hotseat bar.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="hotseatSpecsId" format="reference" />
+        <!-- defaults to hotseatSpecsId, if not specified -->
         <attr name="hotseatSpecsTwoPanelId" format="reference" />
         <!-- File that contains the specs for workspace icon and text size.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="workspaceCellSpecsId" format="reference" />
+        <!-- defaults to workspaceCellSpecsId, if not specified -->
         <attr name="workspaceCellSpecsTwoPanelId" format="reference" />
         <!-- File that contains the specs for all apps icon and text size.
         Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled -->
         <attr name="allAppsCellSpecsId" format="reference" />
+        <!-- defaults to allAppsCellSpecsId, if not specified -->
         <attr name="allAppsCellSpecsTwoPanelId" format="reference" />
 
         <!-- By default all categories are enabled -->
@@ -571,6 +575,7 @@
 
     <declare-styleable name="WidgetsListRowHeader">
         <attr name="appIconSize" format="dimension" />
+        <attr name="collapsable" format="boolean" />
     </declare-styleable>
 
     <attr name="materialColorOnSecondaryFixedVariant" format="color" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 6c3b54c..a620eb0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -71,10 +71,10 @@
     <color name="folder_background_dark">#1F2020</color>
 
     <color name="folder_preview_light">#7FCFFF</color>
-    <color name="folder_preview_dark">#2A2A2A</color>
+    <color name="folder_preview_dark">#1E1F20</color>
 
-    <color name="folder_pagination_color_light">#0B57D0</color>
-    <color name="folder_pagination_color_dark">#A8C7FA</color>
+    <color name="pagination_indicator_dot_color_light">#0B57D0</color>
+    <color name="pagination_indicator_dot_color_dark">#A8C7FA</color>
 
     <color name="text_color_primary_dark">#FFFFFFFF</color>
     <color name="text_color_secondary_dark">#FFFFFFFF</color>
@@ -113,6 +113,8 @@
     <color name="widget_picker_selected_tab_text_color_light">#FFFFFF</color>
     <color name="widget_picker_unselected_tab_text_color_light">#444746</color>
     <color name="widget_picker_collapse_handle_color_light">#C4C7C5</color>
+    <color name="widget_picker_add_button_background_color_light">#0B57D0</color>
+    <color name="widget_picker_add_button_text_color_light">#0B57D0</color>
 
     <color name="widget_picker_primary_surface_color_dark">#1F2020</color>
     <color name="widget_picker_secondary_surface_color_dark">#393939</color>
@@ -128,6 +130,8 @@
     <color name="widget_picker_selected_tab_text_color_dark">#2D312F</color>
     <color name="widget_picker_unselected_tab_text_color_dark">#C4C7C5</color>
     <color name="widget_picker_collapse_handle_color_dark">#444746</color>
+    <color name="widget_picker_add_button_background_color_dark">#062E6F</color>
+    <color name="widget_picker_add_button_text_color_dark">#FFFFFF</color>
 
     <color name="material_color_on_secondary_fixed_variant">#3F4759</color>
     <color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2980635..393a197 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -17,34 +17,22 @@
     <!-- Miscellaneous -->
     <bool name="config_largeHeap">false</bool>
 
-    <integer name="extracted_color_gradient_alpha">153</integer>
-
     <!-- A string pointer to the original app name string. This allows derived projects to
      easily override the app name without providing all translations -->
     <string name="derived_app_name" translatable="false">@string/app_name</string>
 
-    <!-- String representing the intent for search on the apps market. To specify a query, add
-    q=<query> to the data to the intent -->
-    <string name="market_search_intent" translatable="false">market://search?c=apps</string>
-
     <!-- String representing the intent to delete a package.-->
     <string name="delete_package_intent" translatable="false">#Intent;action=android.intent.action.DELETE;launchFlags=0x10800000;end</string>
 
     <!-- String representing the fragment class for settings activity.-->
     <string name="settings_fragment_name" translatable="false">com.android.launcher3.settings.SettingsActivity$LauncherSettingsFragment</string>
 
-    <!-- DragController -->
-    <item type="id" name="drag_event_parity" />
-
     <!-- AllApps & Launcher transitions -->
-    <!-- The duration of the animation from search hint to text entry -->
-    <integer name="config_searchHintAnimationDuration">50</integer>
-
     <!-- The duration of the PagedView page snap animation -->
     <integer name="config_pageSnapAnimationDuration">750</integer>
 
-    <!-- View tag key used to store SpringAnimation data. -->
-    <item type="id" name="spring_animation_tag" />
+    <!-- The duration of the PagedView page snap animation -->
+    <integer name="config_keyboardTaskFocusSnapAnimationDuration">750</integer>
 
     <!-- View tag key used to determine if we should fade in the child views.. -->
     <string name="popup_container_iterate_children" translatable="false">popup_container_iterate_children</string>
@@ -86,77 +74,36 @@
     <string name="widget_holder_factory_class" translatable="false"></string>
     <string name="taskbar_search_session_controller_class" translatable="false"></string>
     <string name="taskbar_model_callbacks_factory_class" translatable="false"></string>
+    <string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
     <string name="launcher_restore_event_logger_class" translatable="false"></string>
-
-    <!-- View ID to use for QSB widget -->
-    <item type="id" name="qsb_widget" />
-
-    <!-- View ID used by cell layout to jail its content -->
-    <item type="id" name="cell_layout_jail_id" />
-
-    <!-- View IDs to store item highlight information -->
-    <item type="id" name="view_unhighlight_background" />
-
-    <!-- view ID used to restore work tab state -->
-    <item type="id" name="work_tab_state_id" />
-
-    <!-- Menu id for feature flags -->
-    <item type="id" name="menu_apply_flags" />
+    <!--  Used for determining category of a widget presented in widget recommendations. -->
+    <string name="widget_recommendation_category_provider_class" translatable="false"></string>
+    <string name="api_wrapper_class" translatable="false"></string>
 
     <!-- Default packages -->
     <string name="wallpaper_picker_package" translatable="false"></string>
     <string name="local_colors_extraction_class" translatable="false"></string>
     <string name="search_session_manager_class" translatable="false"></string>
-
-    <!-- Accessibility actions -->
-    <item type="id" name="action_remove" />
-    <item type="id" name="action_uninstall" />
-    <item type="id" name="action_reconfigure" />
-    <item type="id" name="action_add_to_workspace" />
-    <item type="id" name="action_move" />
-    <item type="id" name="action_move_to_workspace" />
-    <item type="id" name="action_move_screen_backwards" />
-    <item type="id" name="action_move_screen_forwards" />
-    <item type="id" name="action_resize" />
-    <item type="id" name="action_deep_shortcuts" />
-    <item type="id" name="action_shortcuts_and_notifications"/>
-    <item type="id" name="action_dismiss_notification" />
-    <item type="id" name="action_remote_action_shortcut" />
-    <item type="id" name="action_dismiss_prediction" />
-    <item type="id" name="action_pin_prediction"/>
-
-    <!-- QSB IDs. DO not change -->
-    <item type="id" name="search_container_workspace" />
-    <item type="id" name="search_container_all_apps" />
-    <item type="id" name="search_container_hotseat" />
+    <string name="plugin_manager_wrapper_class" translatable="false"></string>
 
     <!-- Scalable Grid configuration -->
     <!-- This is a float because it is converted to dp later in DeviceProfile -->
     <dimen name="hotseat_bar_bottom_space_default">48</dimen>
     <dimen name="hotseat_qsb_space_default">0</dimen>
 
-    <!-- Recents -->
-    <item type="id" name="overview_panel"/>
-
     <!-- Whether to enable background preloading of task thumbnails. -->
     <bool name="config_enableTaskSnapshotPreloading">true</bool>
 
     <!-- Configuration resources -->
-    <item name="all_apps_spring_damping_ratio" type="dimen" format="float">0.75</item>
-    <item name="all_apps_spring_stiffness" type="dimen" format="float">600</item>
-
     <item name="dismiss_task_trans_y_damping_ratio" type="dimen" format="float">0.73</item>
     <item name="dismiss_task_trans_y_stiffness" type="dimen" format="float">800</item>
 
-    <item name="dismiss_task_trans_x_damping_ratio" type="dimen" format="float">0.73</item>
-    <item name="dismiss_task_trans_x_stiffness" type="dimen" format="float">800</item>
-
-    <item name="horizontal_spring_damping_ratio" type="dimen" format="float">0.8</item>
-    <item name="horizontal_spring_stiffness" type="dimen" format="float">250</item>
-
     <item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
     <item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
     <item name="swipe_up_rect_scale_higher_stiffness" type="dimen" format="float">400</item>
+    <!-- Flag: enableScalingRevealHomeAnimation() -->
+    <item name="swipe_up_rect_scale_damping_ratio_v2" type="dimen" format="float">0.8</item>
+    <item name="swipe_up_rect_scale_stiffness_v2" type="dimen" format="float">650</item>
 
     <item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
 
@@ -164,6 +111,11 @@
 
     <item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
     <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
+    <!-- Flag: enableScalingRevealHomeAnimation() -->
+    <item name="swipe_up_rect_x_damping_ratio" type="dimen" format="float">0.965</item>
+    <item name="swipe_up_rect_x_stiffness" type="dimen" format="float">300</item>
+    <item name="swipe_up_rect_y_damping_ratio" type="dimen" format="float">0.95</item>
+    <item name="swipe_up_rect_y_stiffness" type="dimen" format="float">190</item>
 
     <!-- Taskbar -->
     <!-- This is a float because it is converted to dp later in DeviceProfile -->
@@ -188,6 +140,12 @@
     <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
     <dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
     <dimen name="swipe_up_max_velocity">7.619dp</dimen>
+    <!-- Flag: enableScalingRevealHomeAnimation() -->
+    <item name="swipe_up_min_velocity_x_px_per_s" type="dimen" format="integer">300</item>
+    <item name="swipe_up_max_velocity_x_px_per_s" type="dimen" format="integer">500</item>
+    <item name="swipe_up_min_velocity_y_px_per_s" type="dimen" format="integer">2000</item>
+    <item name="swipe_up_max_velocity_y_px_per_s" type="dimen" format="integer">5000</item>
+    <item name="swipe_up_max_velocity_fall_off_factor" type="dimen" format="float">1.4</item>
 
     <array name="dynamic_resources">
         <item>@dimen/swipe_up_scale_start</item>
@@ -196,12 +154,13 @@
 
     <string-array name="filtered_components" ></string-array>
 
-    <!-- Name of the class used to generate colors from the wallpaper colors. Must be implementing the LauncherAppWidgetHostView.ColorGenerator interface. -->
-    <string name="color_generator_class" translatable="false"/>
+    <!-- Widget component names to be included in weather category of widget suggestions. -->
+    <string-array name="weather_recommendations"></string-array>
+    <!-- Widget component names to be included in fitness category of widget suggestions. -->
+    <string-array name="fitness_recommendations"></string-array>
 
     <!-- Swipe back to home related -->
     <dimen name="swipe_back_window_scale_x_margin">10dp</dimen>
-    <dimen name="swipe_back_window_max_delta_y">160dp</dimen>
     <dimen name="swipe_back_window_corner_radius">40dp</dimen>
 
     <!-- The duration of the bottom sheet opening and closing animation -->
@@ -254,4 +213,13 @@
 
     <!--  Used for custom widgets  -->
     <array name="custom_widget_providers"/>
+
+    <!-- Embed parameters -->
+    <dimen name="activity_split_ratio"  format="float">0.5</dimen>
+    <integer name="min_width_split">720</integer>
+
+    <!-- Skip "Install to private" long-press shortcut packages name -->
+    <string-array name="skip_private_profile_shortcut_packages" translatable="false">
+        <item>com.android.settings</item>
+    </string-array>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0a57127..5dd3569 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -22,7 +22,7 @@
     <dimen name="dynamic_grid_edge_margin">10.77dp</dimen>
     <dimen name="dynamic_grid_left_right_margin">8dp</dimen>
     <!-- Minimum amount of next page visible in spring loaded mode -->
-    <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
+    <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">48dp</dimen>
 
     <dimen name="dynamic_grid_cell_border_spacing">16dp</dimen>
     <dimen name="cell_layout_padding">10.77dp</dimen>
@@ -31,6 +31,7 @@
     <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_bottom_tall_padding">0dp</dimen>
     <dimen name="spring_loaded_hotseat_top_margin">76dp</dimen>
+    <dimen name="spring_loaded_hotseat_top_margin_wide_portrait">64dp</dimen>
 
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
 
@@ -47,6 +48,7 @@
     <dimen name="drop_target_vertical_gap">20dp</dimen>
     <dimen name="drop_target_top_margin">32dp</dimen>
     <dimen name="drop_target_bottom_margin">16dp</dimen>
+    <dimen name="drop_target_bottom_margin_wide_portrait">32dp</dimen>
 
     <!-- App Widget resize frame -->
     <!-- Button drop target bar -->
@@ -56,7 +58,7 @@
     <!-- App Widget resize frame -->
     <dimen name="widget_handle_margin">13dp</dimen>
     <dimen name="resize_frame_background_padding">24dp</dimen>
-    <dimen name="resize_frame_margin">22dp</dimen>
+    <dimen name="resize_frame_margin">23dp</dimen>
     <dimen name="resize_frame_invalid_drag_across_two_panel_opacity_margin">24dp</dimen>
 
     <!-- App widget reconfigure button -->
@@ -103,6 +105,7 @@
     <dimen name="all_apps_search_bar_content_overlap">24dp</dimen>
     <dimen name="all_apps_search_bar_bottom_padding">30dp</dimen>
     <dimen name="all_apps_empty_search_message_top_offset">40dp</dimen>
+    <dimen name="all_apps_search_top_row_extra_height">4dp</dimen>
     <dimen name="all_apps_header_pill_height">48dp</dimen>
     <dimen name="all_apps_header_pill_corner_radius">12dp</dimen>
     <dimen name="all_apps_header_tab_height">48dp</dimen>
@@ -144,17 +147,20 @@
     <dimen name="work_fab_height">56dp</dimen>
     <dimen name="work_fab_radius">16dp</dimen>
     <dimen name="work_fab_icon_size">24dp</dimen>
-    <dimen name="work_fab_text_start_margin">8dp</dimen>
+    <dimen name="work_fab_icon_end_margin">12dp</dimen>
+    <dimen name="work_fab_text_end_margin">16dp</dimen>
     <dimen name="work_card_padding_horizontal">10dp</dimen>
     <dimen name="work_fab_width">214dp</dimen>
     <dimen name="work_card_button_height">52dp</dimen>
     <dimen name="work_fab_margin">16dp</dimen>
     <dimen name="work_fab_margin_bottom">20dp</dimen>
-    <dimen name="work_mode_fab_padding">16dp</dimen>
+    <dimen name="work_mode_fab_background_start_padding">16dp</dimen>
+    <dimen name="work_mode_fab_background_end_padding">4dp</dimen>
     <dimen name="work_profile_footer_padding">20dp</dimen>
     <dimen name="work_edu_card_margin">16dp</dimen>
     <dimen name="work_edu_card_radius">16dp</dimen>
     <dimen name="work_edu_card_bottom_margin">26dp</dimen>
+    <dimen name="work_edu_card_text_end_margin">32dp</dimen>
     <dimen name="work_apps_paused_button_stroke">1dp</dimen>
 
     <dimen name="work_card_margin">24dp</dimen>
@@ -172,17 +178,21 @@
 
     <!-- Widget tray -->
     <dimen name="widget_cell_vertical_padding">8dp</dimen>
-    <dimen name="widget_cell_horizontal_padding">16dp</dimen>
+    <dimen name="widget_cell_horizontal_padding">8dp</dimen>
     <dimen name="widget_cell_font_size">14sp</dimen>
+    <dimen name="widget_cell_app_icon_size">24dp</dimen>
+    <dimen name="widget_cell_app_icon_padding">8dp</dimen>
+    <dimen name="widget_cell_add_button_height">48dp</dimen>
+    <dimen name="widget_cell_add_button_start_padding">8dp</dimen>
+    <dimen name="widget_cell_add_button_end_padding">16dp</dimen>
+    <dimen name="widget_cell_add_button_scroll_padding">24dp</dimen>
 
     <dimen name="widget_tabs_button_horizontal_padding">4dp</dimen>
     <dimen name="widget_tabs_horizontal_padding">16dp</dimen>
     <dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
     <dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
     <dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
-
-    <dimen name="recommended_widgets_table_vertical_padding">8dp</dimen>
-
+    <dimen name="widget_recommendations_table_vertical_padding">8dp</dimen>
     <!-- Bottom margin for the search and recommended widgets container without work profile -->
     <dimen name="search_and_recommended_widgets_container_bottom_margin">16dp</dimen>
     <!-- Bottom margin for the search and recommended widgets container with work profile -->
@@ -193,8 +203,12 @@
 
     <dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
     <dimen name="widget_list_entry_spacing">2dp</dimen>
-    <dimen name="widget_list_horizontal_margin">16dp</dimen>
+    <!-- Less margin on sides to let widgets table width be close to the workspace width. -->
+    <dimen name="widget_list_horizontal_margin">11dp</dimen>
+    <!-- Margin applied to the recycler view with search bar & the list of widget apps below it. -->
+    <dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
     <dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
+    <dimen name="widget_picker_vertical_margin_right_pane">24dp</dimen>
 
     <dimen name="widget_preview_shadow_blur">0.5dp</dimen>
     <dimen name="widget_preview_key_shadow_distance">1dp</dimen>
@@ -266,7 +280,6 @@
 
     <!-- Sizes for managed profile badges -->
     <dimen name="profile_badge_size">24dp</dimen>
-    <dimen name="profile_badge_margin">5dp</dimen>
     <dimen name="profile_badge_minimum_top">2dp</dimen>
 
     <!-- Shadows and outlines -->
@@ -368,6 +381,11 @@
     <!-- Taskbar related (placeholders to compile in Launcher3 without Quickstep) -->
     <dimen name="taskbar_size">0dp</dimen>
     <dimen name="taskbar_phone_size">@*android:dimen/navigation_bar_frame_height</dimen>
+    <dimen name="taskbar_phone_home_button_size">80dp</dimen>
+    <dimen name="taskbar_phone_content_padding">8dp</dimen>
+    <dimen name="taskbar_phone_rounded_corner_content_margin">
+        @*android:dimen/rounded_corner_content_padding
+    </dimen>
     <dimen name="taskbar_stashed_size">0dp</dimen>
     <dimen name="qsb_widget_height">0dp</dimen>
     <dimen name="qsb_shadow_height">0dp</dimen>
@@ -384,7 +402,7 @@
     <dimen name="transient_taskbar_clamped_offset_bound">0dp</dimen>
     <dimen name="taskbar_icon_spacing">0dp</dimen>
     <dimen name="taskbar_nav_buttons_size">0dp</dimen>
-    <dimen name="taskbar_contextual_button_margin">0dp</dimen>
+    <dimen name="taskbar_contextual_button_suw_margin">0dp</dimen>
     <dimen name="taskbar_hotseat_nav_spacing">0dp</dimen>
     <dimen name="taskbar_button_margin_default">0dp</dimen>
     <dimen name="taskbar_button_space_inbetween">0dp</dimen>
@@ -392,6 +410,9 @@
     <dimen name="taskbar_button_margin_split">0dp</dimen>
     <dimen name="taskbar_button_margin_6_5">0dp</dimen>
 
+    <!--- Floating Ime Inset height-->
+    <dimen name="floating_ime_inset_height">0dp</dimen>
+
     <!-- Bubble bar (placeholders to compile in Launcher3 without Quickstep) -->
     <dimen name="bubblebar_hotseat_adjustment_threshold">0dp</dimen>
 
@@ -405,11 +426,6 @@
     <dimen name="task_thumbnail_icon_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_drawable_size_grid">0dp</dimen>
-    <dimen name="task_thumbnail_icon_menu_max_width">0dp</dimen>
-    <dimen name="task_thumbnail_icon_menu_start_margin">0dp</dimen>
-    <dimen name="task_thumbnail_icon_menu_background_max_width">0dp</dimen>
-    <dimen name="task_thumbnail_icon_menu_corner_radius">0dp</dimen>
-    <dimen name="task_thumbnail_icon_menu_drawable_size">0dp</dimen>
     <dimen name="task_thumbnail_icon_menu_drawable_touch_size">0dp</dimen>
     <dimen name="task_menu_edge_padding">0dp</dimen>
     <dimen name="overview_task_margin">0dp</dimen>
@@ -435,6 +451,15 @@
     <dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
     <dimen name="split_instructions_start_margin_cancel">8dp</dimen>
+    <dimen name="split_divider_handle_region_width">96dp</dimen>
+    <dimen name="split_divider_handle_region_height">48dp</dimen>
+
+    <dimen name="focus_outline_radius">16dp</dimen>
+    <dimen name="focus_inner_outline_radius">14dp</dimen>
+    <dimen name="focus_outline_stroke_width">2dp</dimen>
+    <!-- -4dp for double stroke focus outlines, -2dp for padding between outline and widget,
+    make it negative to outset the rect and leave space for drawing focus outline and padding -->
+    <dimen name="focus_rect_widget_outsets">-6dp</dimen>
 
     <!-- Workspace grid visualization parameters -->
     <dimen name="grid_visualization_rounding_radius">16dp</dimen>
@@ -447,7 +472,6 @@
     <dimen name="padded_rounded_button_padding">8dp</dimen>
 
     <!-- Bottom sheet related parameters -->
-    <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
     <dimen name="bottom_sheet_handle_area_height">36dp</dimen>
     <dimen name="bottom_sheet_handle_width">32dp</dimen>
     <dimen name="bottom_sheet_handle_height">4dp</dimen>
@@ -469,12 +493,24 @@
     <dimen name="ps_container_corner_radius">24dp</dimen>
     <dimen name="ps_header_height">64dp</dimen>
     <dimen name="ps_header_relative_layout_height">48dp</dimen>
-    <dimen name="ps_header_image_height">36dp</dimen>
+    <dimen name="ps_header_image_height">48dp</dimen>
     <dimen name="ps_header_text_height">24dp</dimen>
     <dimen name="ps_header_layout_margin">16dp</dimen>
-    <dimen name="ps_header_settings_icon_margin_end">8dp</dimen>
+    <dimen name="ps_lock_button_margin_end">12dp</dimen>
     <dimen name="ps_header_text_size">16sp</dimen>
-    <dimen name="ps_button_height">36dp</dimen>
-    <dimen name="ps_button_width">36dp</dimen>
+    <dimen name="ps_button_height">40dp</dimen>
+    <dimen name="ps_button_width">40dp</dimen>
     <dimen name="ps_lock_button_width">89dp</dimen>
+    <dimen name="ps_app_divider_padding">16dp</dimen>
+    <dimen name="ps_extra_bottom_padding">16dp</dimen>
+    <dimen name="ps_lock_corner_radius">20dp</dimen>
+    <dimen name="ps_lock_icon_size">20dp</dimen>
+    <dimen name="ps_lock_icon_margin_top">10dp</dimen>
+    <dimen name="ps_lock_icon_margin_bottom">10dp</dimen>
+    <dimen name="ps_lock_icon_text_margin_start_expanded">8dp</dimen>
+    <dimen name="ps_lock_icon_text_margin_end_expanded">6dp</dimen>
+    <dimen name="ps_lock_button_background_padding">10dp</dimen>
+
+    <!-- WindowManagerProxy -->
+    <dimen name="max_width_and_height_of_small_display_cutout">136px</dimen>
 </resources>
diff --git a/res/values/id.xml b/res/values/id.xml
index 6156c91..7bb9396 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -23,6 +23,40 @@
     <item type="id" name="split_topLeft_appInfo" />
     <item type="id" name="split_bottomRight_appInfo" />
 
+    <!-- Accessibility actions -->
+    <item type="id" name="action_remove" />
+    <item type="id" name="action_uninstall" />
+    <item type="id" name="action_reconfigure" />
+    <item type="id" name="action_add_to_workspace" />
+    <item type="id" name="action_move" />
+    <item type="id" name="action_move_to_workspace" />
+    <item type="id" name="action_move_screen_backwards" />
+    <item type="id" name="action_move_screen_forwards" />
+    <item type="id" name="action_resize" />
+    <item type="id" name="action_deep_shortcuts" />
+    <item type="id" name="action_remote_action_shortcut" />
+    <item type="id" name="action_dismiss_prediction" />
+    <item type="id" name="action_pin_prediction"/>
+
+    <!-- QSB IDs. DO not change -->
+    <item type="id" name="search_container_workspace" />
+    <item type="id" name="search_container_all_apps" />
+    <item type="id" name="search_container_hotseat" />
+
+    <!-- View ID to use for QSB widget -->
+    <item type="id" name="qsb_widget" />
+
+    <!-- View ID used by cell layout to jail its content -->
+    <item type="id" name="cell_layout_jail_id" />
+
+    <!-- View IDs to store item highlight information -->
+    <item type="id" name="view_unhighlight_background" />
+
+    <!-- view ID used to restore work tab state -->
+    <item type="id" name="work_tab_state_id" />
+
+    <!-- Menu id for feature flags -->
+    <item type="id" name="menu_apply_flags" />
 
     <!--  Do not change, must be kept in sync with sysui navbar button IDs for tests!  -->
     <item type="id" name="home" />
@@ -32,6 +66,7 @@
     <item type="id" name="ime_switcher" />
     <item type="id" name="accessibility_button" />
     <item type="id" name="rotate_suggestion" />
+    <item type="id" name="space" />
     <!--  /Do not change, must be kept in sync with sysui navbar button IDs for tests!  -->
 
     <item type="id" name="quick_settings_button" />
@@ -39,6 +74,7 @@
     <item type="id" name="cache_entry_tag_id" />
 
     <item type="id" name="saved_clip_children_tag_id" />
+    <item type="id" name="saved_clip_to_padding_tag_id" />
 
     <item type="id" name="saved_floating_widget_foreground" />
     <item type="id" name="saved_floating_widget_background" />
@@ -51,4 +87,13 @@
     <item type="id" name="ps_settings_button" />
     <item type="id" name="ps_transition_image" />
 
+    <!-- Recents -->
+    <item type="id" name="overview_panel"/>
+
+    <!-- DragController -->
+    <item type="id" name="drag_event_parity" />
+
+    <!-- View tag key used to store SpringAnimation data. -->
+    <item type="id" name="spring_animation_tag" />
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6a4a9a4..e1c7d64 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -46,6 +46,12 @@
     <string name="save_app_pair">Save app pair</string>
     <!-- App pair default title -->
     <string name="app_pair_default_title"><xliff:g id="app1" example="Chrome">%1$s</xliff:g> | <xliff:g id="app2" example="YouTube">%2$s</xliff:g></string>
+    <!-- Displayed when an app pair can't launch at this screen size [CHAR_LIMIT=none] -->
+    <string name="app_pair_unlaunchable_at_screen_size">This app pair isn\'t supported on this device</string>
+    <!-- Displayed when an app pair can't launch at this screen size, but user can unfold device to restore functionality [CHAR_LIMIT=none] -->
+    <string name="app_pair_needs_unfold">Unfold device to use this app pair</string>
+    <!-- Displayed when user selects a shortcut for an app pair that is currently not available [CHAR_LIMIT=none]-->
+    <string name="app_pair_not_available">App pair isn\'t available</string>
 
     <!-- Widgets -->
     <!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
@@ -60,6 +66,12 @@
     <!-- Spoken text for a screen reader. The placeholder text is the widget name.
          [CHAR_LIMIT=none]-->
     <string name="widget_preview_context_description"><xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
+    <!-- Spoken text for a screen reader. The first placeholder text is the widget name, the
+         remaining placeholders are for the widget dimensions.
+         [CHAR_LIMIT=none]-->
+    <string name="widget_preview_name_and_dims_content_description">
+        <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget, %2$d wide by %3$d high
+    </string>
     <!-- Message to tell the user to press and hold a widget/icon to add it to the home screen.
          [CHAR LIMIT=NONE]  -->
     <string name="add_item_request_drag_hint">Touch &amp; hold the widget to move it around the home screen</string>
@@ -71,6 +83,16 @@
     <!-- Widget suggestions header title in the full widgets picker for large screen devices
     in landscape mode. [CHAR_LIMIT=50] -->
     <string name="suggested_widgets_header_title">Suggestions</string>
+    <string name="productivity_widget_recommendation_category_label">Essentials</string>
+    <string name="news_widget_recommendation_category_label">News &amp; magazines</string>
+    <string name="social_and_entertainment_widget_recommendation_category_label">Your Chill Zone</string>
+    <string name="entertainment_widget_recommendation_category_label">Entertainment</string>
+    <string name="social_widget_recommendation_category_label">Social</string>
+    <string name="fitness_widget_recommendation_category_label">Health &amp; fitness</string>
+    <string name="weather_widget_recommendation_category_label">Weather</string>
+    <string name="others_widget_recommendation_category_label">Suggested for you</string>
+    <!-- accessibilityPaneTitle for the right pane when showing suggested widgets. -->
+    <string name="widget_picker_right_pane_accessibility_title"><xliff:g id="selected_header" example="Calendar">%1$s</xliff:g> widgets on right, search and options on left</string>
     <!-- Label for showing the number of widgets an app has in the full widgets picker.
          [CHAR_LIMIT=25][ICU SYNTAX] -->
     <string name="widgets_count">
@@ -111,6 +133,12 @@
     <!-- A widget category label for grouping widgets related to note taking. [CHAR_LIMIT=30] -->
     <string name="widget_category_note_taking">Note-taking</string>
 
+    <!-- Text on the button that adds a widget to the home screen. [CHAR_LIMIT=15] -->
+    <string name="widget_add_button_label">Add</string>
+    <!-- Accessibility content description for the button that adds a widget to the home screen. The
+         placeholder text is the widget name. [CHAR_LIMIT=none] -->
+    <string name="widget_add_button_content_description">Add <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
+
     <!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
          [CHAR_LIMIT=NONE] -->
     <string name="widget_education_header">Useful info at your fingertips</string>
@@ -171,9 +199,11 @@
     <string name="uninstall_drop_target_label">Uninstall</string>
     <!-- Label for app info drop target. [CHAR_LIMIT=20] -->
     <string name="app_info_drop_target_label">App info</string>
+    <!-- Label for install to private profile shortcut label. [CHAR_LIMIT=20] -->
+    <string name="install_private_system_shortcut_label">Install in private</string>
     <!-- Label for install drop target. [CHAR_LIMIT=20] -->
     <string name="install_drop_target_label">Install</string>
-    <!-- Label for install dismiss prediction. -->
+    <!-- Label for dismiss prediction. -->
     <string name="dismiss_prediction_label">Don\'t suggest app</string>
     <!-- Label for pinning predicted app. -->
     <string name="pin_prediction">Pin Prediction</string>
@@ -312,6 +342,8 @@
     <string name="app_downloading_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> downloading, <xliff:g id="progress" example="30%">%2$s</xliff:g> complete</string>
     <!-- Title for an app whose download has been started. -->
     <string name="app_waiting_download_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> waiting to install</string>
+    <!-- Title for an app which is archived. -->
+    <string name="app_archived_title"><xliff:g id="name" example="Messenger">%1$s</xliff:g> is archived. Tap to download.</string>
 
 
     <!-- Title shown on the alert dialog prompting the user to update the application in market
@@ -400,9 +432,6 @@
 
     <!-- Accessibility action to show quick actions menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_deep_shortcut">Shortcuts</string>
-    <!-- Accessibility description when the context menu of a launcher icon that has notifications as well as shortcuts (providing quick access to app's actions). The "shortcuts" translation should be consistent with the one for action_deep_shortcut. [CHAR_LIMIT=50] -->
-    <string name="shortcuts_menu_with_notifications_description">Shortcuts and notifications
-    </string>
 
     <!-- Accessibility action to dismiss a notification in the shortcuts menu for an icon. [CHAR_LIMIT=30] -->
     <string name="action_dismiss_notification">Dismiss</string>
@@ -410,9 +439,6 @@
     <!-- Content description for arrow tip close button. [CHAR LIMIT=NONE] -->
     <string name="accessibility_close">Close</string>
 
-    <!-- Accessibility confirmation for notification being dismissed. -->
-    <string name="notification_dismissed">Notification dismissed</string>
-
     <!-- Label of tab to indicate personal apps -->
     <string name="all_apps_personal_tab">Personal</string>
 
@@ -425,6 +451,8 @@
     <string name="work_profile_edu_work_apps">Work apps are badged and visible to your IT admin</string>
     <!-- Action label to finish work profile edu-->
     <string name="work_profile_edu_accept">Got it</string>
+    <!-- Info icon unicode for alpha scroller when work edu card is present -->
+    <string name="work_profile_edu_section" translatable="false">\u24D8</string>
 
     <!--- heading shown when user opens work apps tab while work apps are paused -->
     <string name="work_apps_paused_title">Work apps are paused</string>
@@ -451,16 +479,23 @@
     <string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
 
     <!-- Strings for Private Space -->
-    <!-- Private space label -->
+    <!-- Private space tile label -->
     <string name="private_space_label">Private space</string>
+    <!-- Private space tile secondary label -->
+    <string name="private_space_secondary_label">Tap to set up or open</string>
     <!-- Title for Private Space Container shown at the bottom of all apps drawer -->
     <string name="ps_container_title">Private</string>
     <!-- Description for Private Space Settings button -->
     <string name="ps_container_settings">Private Space Settings</string>
     <!-- Description for Private Space Lock/Unlock button -->
     <string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
+    <string name="ps_container_lock_title">Lock</string>
     <!-- Description for Private Space Transition button -->
     <string name="ps_container_transition">Private Space Transitioning</string>
+    <!-- Title for Private Space install app icon -->
+    <string name="ps_add_button_label">Install apps</string>
+    <!-- Content description for install app icon -->
+    <string name="ps_add_button_content_description">Install apps to Private Space</string>
 
     <!-- Strings for bubble bar -->
     <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 36991b1..00b962e 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -52,13 +52,16 @@
         <item name="workspaceAmbientShadowColor">#40000000</item>
         <item name="workspaceKeyShadowColor">#89000000</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
-        <item name="folderPaginationColor">@color/folder_pagination_color_light</item>
+        <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_light</item>
+        <item name="focusOutlineColor">@color/material_color_secondary_fixed</item>
+        <item name="focusInnerOutlineColor">@color/material_color_on_secondary_fixed_variant</item>
         <item name="folderPreviewColor">@color/folder_preview_light</item>
         <item name="folderBackgroundColor">@color/folder_background_light</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
         <item name="isFolderDarkText">true</item>
         <item name="folderTextColor">@color/folder_text_color_light</item>
         <item name="folderHintTextColor">@color/folder_hint_text_color_light</item>
+        <item name="appPairSurfaceInFolder">@color/material_color_surface_container_lowest</item>
         <item name="loadingIconColor">#CCFFFFFF</item>
         <item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
         <item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
@@ -163,13 +166,14 @@
         <item name="popupShadeThird">@color/popup_shade_third_dark</item>
         <item name="notificationDotColor">@color/notification_dot_color_dark</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
-        <item name="folderPaginationColor">@color/folder_pagination_color_dark</item>
+        <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_dark</item>
         <item name="folderPreviewColor">@color/folder_preview_dark</item>
         <item name="folderBackgroundColor">@color/folder_background_dark</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
         <item name="isFolderDarkText">false</item>
         <item name="folderTextColor">@color/folder_text_color_dark</item>
         <item name="folderHintTextColor">@color/folder_hint_text_color_dark</item>
+        <item name="appPairSurfaceInFolder">@color/material_color_surface_container_lowest</item>
         <item name="isMainColorDark">true</item>
         <item name="loadingIconColor">#99FFFFFF</item>
         <item name="iconOnlyShortcutColor">#B3FFFFFF</item>
@@ -260,6 +264,10 @@
             @color/widget_picker_unselected_tab_text_color_light</item>
         <item name="widgetPickerCollapseHandleColor">
             @color/widget_picker_collapse_handle_color_light</item>
+        <item name="widgetPickerAddButtonBackgroundColor">
+            @color/widget_picker_add_button_background_color_light</item>
+        <item name="widgetPickerAddButtonTextColor">
+            @color/widget_picker_add_button_text_color_light</item>
     </style>
     <style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
         <item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
@@ -291,6 +299,10 @@
             @color/widget_picker_unselected_tab_text_color_dark</item>
         <item name="widgetPickerCollapseHandleColor">
             @color/widget_picker_collapse_handle_color_dark</item>
+        <item name="widgetPickerAddButtonBackgroundColor">
+            @color/widget_picker_add_button_background_color_dark</item>
+        <item name="widgetPickerAddButtonTextColor">
+            @color/widget_picker_add_button_text_color_dark</item>
     </style>
 
     <style name="FastScrollerPopup" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
@@ -440,5 +452,6 @@
         <item name="android:textSize">16sp</item>
         <item name="android:textColor">@color/material_color_on_surface</item>
         <item name="android:fontFamily">google-sans-text-medium</item>
+        <item name="android:ellipsize">end</item>
     </style>
 </resources>
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index c9a44a1..1d0dbff 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -168,7 +168,6 @@
         launcher:numFolderRows="3"
         launcher:numFolderColumns="3"
         launcher:numHotseatIcons="6"
-        launcher:hotseatColumnSpanLandscape="4"
         launcher:numAllAppsColumns="6"
         launcher:isScalable="true"
         launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_6_5"
diff --git a/res/xml/split_configuration.xml b/res/xml/split_configuration.xml
new file mode 100644
index 0000000..531fef8
--- /dev/null
+++ b/res/xml/split_configuration.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources
+    xmlns:window="http://schemas.android.com/apk/res-auto">
+    <!-- Automatically split the following activity pairs. -->
+    <SplitPairRule
+        window:splitRatio="@dimen/activity_split_ratio"
+        window:splitLayoutDirection="locale"
+        window:splitMinWidthDp="@integer/min_width_split"
+        window:splitMaxAspectRatioInPortrait="alwaysAllow"
+        window:finishPrimaryWithSecondary="never"
+        window:finishSecondaryWithPrimary="always"
+        window:clearTop="false">
+        <SplitPairFilter
+            window:primaryActivityName="com.android.launcher3.settings.SettingsActivity"
+            window:secondaryActivityName="com.android.launcher3.settings.SettingsActivity"/>
+
+    </SplitPairRule>
+</resources>
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
deleted file mode 100644
index ce13bfb..0000000
--- a/settings.gradle
+++ /dev/null
@@ -1,5 +0,0 @@
-include ':IconLoader'
-project(':IconLoader').projectDir = new File(rootDir, 'iconloaderlib')
-
-include ':SharedLibWrapper'
-project(':SharedLibWrapper').projectDir = new File(rootDir, 'SharedLibWrapper')
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index f72c556..4ccf3db 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -124,7 +124,8 @@
 
     /** Type of popups that should get exclusive accessibility focus. */
     public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
-            & ~TYPE_ALL_APPS_EDU & ~TYPE_TASKBAR_ALL_APPS & ~TYPE_PIN_IME_POPUP;
+            & ~TYPE_ALL_APPS_EDU & ~TYPE_TASKBAR_ALL_APPS & ~TYPE_PIN_IME_POPUP
+            & ~TYPE_WIDGET_RESIZE_FRAME;
 
     // These view all have particular operation associated with swipe down interaction.
     public static final int TYPE_STATUS_BAR_SWIPE_DOWN_DISALLOW = TYPE_WIDGETS_BOTTOM_SHEET |
@@ -277,18 +278,7 @@
 
     public static void closeOpenViews(ActivityContext activity, boolean animate,
             @FloatingViewType int type) {
-        BaseDragLayer dragLayer = activity.getDragLayer();
-        // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
-        // and will be one of the last views.
-        for (int i = dragLayer.getChildCount() - 1; i >= 0; i--) {
-            View child = dragLayer.getChildAt(i);
-            if (child instanceof AbstractFloatingView) {
-                AbstractFloatingView abs = (AbstractFloatingView) child;
-                if (abs.isOfType(type)) {
-                    abs.close(animate);
-                }
-            }
-        }
+        new AbstractFloatingViewHelper().closeOpenViews(activity, animate, type);
     }
 
     public static void closeAllOpenViews(ActivityContext activity, boolean animate) {
diff --git a/src/com/android/launcher3/AbstractFloatingViewHelper.kt b/src/com/android/launcher3/AbstractFloatingViewHelper.kt
new file mode 100644
index 0000000..0bfbc6e
--- /dev/null
+++ b/src/com/android/launcher3/AbstractFloatingViewHelper.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3
+
+import com.android.launcher3.AbstractFloatingView.FloatingViewType
+import com.android.launcher3.views.ActivityContext
+
+/**
+ * Helper class for manaing AbstractFloatingViews which shows a floating UI on top of the launcher
+ * UI.
+ */
+class AbstractFloatingViewHelper {
+    fun closeOpenViews(activity: ActivityContext, animate: Boolean, @FloatingViewType type: Int) {
+        val dragLayer = activity.getDragLayer()
+        // Iterate in reverse order. AbstractFloatingView is added later to the dragLayer,
+        // and will be one of the last views.
+        for (i in dragLayer.getChildCount() - 1 downTo 0) {
+            val child = dragLayer.getChildAt(i)
+            if (child is AbstractFloatingView && child.isOfType(type)) {
+                child.close(animate)
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/Alarm.java b/src/com/android/launcher3/Alarm.java
index e4aebf6..fb8088c 100644
--- a/src/com/android/launcher3/Alarm.java
+++ b/src/com/android/launcher3/Alarm.java
@@ -17,6 +17,7 @@
 package com.android.launcher3;
 
 import android.os.Handler;
+import android.os.Looper;
 import android.os.SystemClock;
 
 public class Alarm implements Runnable{
@@ -33,7 +34,11 @@
     private long mLastSetTimeout;
 
     public Alarm() {
-        mHandler = new Handler();
+        this(Looper.myLooper());
+    }
+
+    public Alarm(Looper looper) {
+        mHandler = new Handler(looper);
     }
 
     public void setOnAlarmListener(OnAlarmListener alarmListener) {
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 79b831e..b46d7e2 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -46,6 +46,7 @@
 import com.android.launcher3.views.ArrowTipView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.ArrayList;
@@ -191,17 +192,19 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        if (Utilities.ATLEAST_Q) {
-            for (int i = 0; i < HANDLE_COUNT; i++) {
-                View dragHandle = mDragHandles[i];
-                mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
-                        dragHandle.getRight(), dragHandle.getBottom());
-            }
-            setSystemGestureExclusionRects(mSystemGestureExclusionRects);
+        for (int i = 0; i < HANDLE_COUNT; i++) {
+            View dragHandle = mDragHandles[i];
+            mSystemGestureExclusionRects.get(i).set(dragHandle.getLeft(), dragHandle.getTop(),
+                    dragHandle.getRight(), dragHandle.getBottom());
         }
+        setSystemGestureExclusionRects(mSystemGestureExclusionRects);
     }
 
     public static void showForWidget(LauncherAppWidgetHostView widget, CellLayout cellLayout) {
+        // If widget is not added to view hierarchy, we cannot show resize frame at correct location
+        if (widget.getParent() == null) {
+            return;
+        }
         Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
         AbstractFloatingView.closeAllOpenViews(launcher);
 
@@ -472,8 +475,11 @@
             mLastDirectionVector[1] = mDirectionVector[1];
         }
 
-        if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView,
-                mDirectionVector, onDismiss)) {
+        // We don't want to evaluate resize if a widget was pending config activity and was already
+        // occupying a space on the screen. This otherwise will cause reorder algorithm evaluate a
+        // different location for the widget and cause a jump.
+        if (!(mWidgetView instanceof PendingAppWidgetHostView) && mCellLayout.createAreaForResize(
+                cellX, cellY, spanX, spanY, mWidgetView, mDirectionVector, onDismiss)) {
             if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY) ) {
                 mStateAnnouncer.announce(
                         mLauncher.getString(R.string.widget_resized, spanX, spanY));
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index c7cdfa8..cf86528 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -52,7 +52,7 @@
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.Partner;
 import com.android.launcher3.util.Thunk;
@@ -203,7 +203,7 @@
         mIdp = LauncherAppState.getIDP(context);
         mRowCount = mIdp.numRows;
         mColumnCount = mIdp.numColumns;
-        mActivityOverride = ApiWrapper.getActivityOverrides(context);
+        mActivityOverride = ApiWrapper.INSTANCE.get(context).getActivityOverrides();
     }
 
     /**
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index f8ed4df..cf93a79 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -20,11 +20,8 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.ActionMode;
-import android.view.Display;
 import android.view.View;
 
 import androidx.annotation.MainThread;
@@ -39,7 +36,6 @@
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.OnColorHintListener;
 import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.WallpaperColorHints;
 import com.android.launcher3.util.WindowBounds;
 
@@ -55,16 +51,12 @@
     public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
 
     private ActionMode mCurrentActionMode;
-    protected boolean mIsSafeModeEnabled;
 
     private int mThemeRes = R.style.AppTheme;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
-                () -> getPackageManager().isSafeMode());
         DisplayController.INSTANCE.get(this).addChangeListener(this);
 
         // Update theme
@@ -119,8 +111,6 @@
         return false;
     }
 
-    public abstract <T extends View> T getOverviewPanel();
-
     public abstract View getRootView();
 
     public void returnToHomescreen() {
@@ -170,19 +160,11 @@
     protected abstract void reapplyUi();
 
     protected WindowBounds getMultiWindowDisplaySize() {
-        if (Utilities.ATLEAST_R) {
-            return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
-        }
-        // Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
-        // the app window size
-        Display display = getWindowManager().getDefaultDisplay();
-        Point mwSize = new Point();
-        display.getSize(mwSize);
-        return new WindowBounds(new Rect(0, 0, mwSize.x, mwSize.y), new Rect());
+        return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
     }
 
     @Override
     public boolean isAppBlockedForSafeMode() {
-        return mIsSafeModeEnabled;
+        return LauncherAppState.getInstance(this).isSafeModeEnabled();
     }
 }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 91da7e6..83236d1 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -19,9 +19,9 @@
 import static android.text.Layout.Alignment.ALIGN_NORMAL;
 
 import static com.android.launcher3.Flags.enableCursorHoverStates;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
 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;
 import static com.android.launcher3.icons.BitmapInfo.FLAG_THEMED;
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
@@ -58,7 +58,6 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
 import com.android.launcher3.dragndrop.DraggableView;
@@ -69,13 +68,13 @@
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.icons.PlaceHolderIconDrawable;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.search.StringMatcherUtility;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.util.SafeCloseable;
@@ -96,10 +95,10 @@
 public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
         IconLabelDotView, DraggableView, Reorderable {
 
-    private static final int DISPLAY_WORKSPACE = 0;
+    public static final int DISPLAY_WORKSPACE = 0;
     public static final int DISPLAY_ALL_APPS = 1;
-    private static final int DISPLAY_FOLDER = 2;
-    protected static final int DISPLAY_TASKBAR = 5;
+    public static final int DISPLAY_FOLDER = 2;
+    public static final int DISPLAY_TASKBAR = 5;
     public static final int DISPLAY_SEARCH_RESULT = 6;
     public static final int DISPLAY_SEARCH_RESULT_SMALL = 7;
     public static final int DISPLAY_PREDICTION_ROW = 8;
@@ -164,6 +163,8 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mHideBadge = false;
     @ViewDebug.ExportedProperty(category = "launcher")
+    private boolean mSkipUserBadge = false;
+    @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mIsIconVisible = true;
     @ViewDebug.ExportedProperty(category = "launcher")
     private int mTextColor;
@@ -188,7 +189,7 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mDisableRelayout = false;
 
-    private HandlerRunnable mIconLoadRequest;
+    private CancellableTask mIconLoadRequest;
 
     private boolean mEnableIconUpdateAnimation = false;
 
@@ -211,6 +212,7 @@
         mIsRtl = (getResources().getConfiguration().getLayoutDirection()
                 == View.LAYOUT_DIRECTION_RTL);
         mDeviceProfile = mActivity.getDeviceProfile();
+        mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
         mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
         final int defaultIconSize;
@@ -235,13 +237,12 @@
             defaultIconSize = getResources().getDimensionPixelSize(
                     R.dimen.search_row_small_icon_size);
         } else if (mDisplay == DISPLAY_TASKBAR) {
-            defaultIconSize = mDeviceProfile.iconSizePx;
+            defaultIconSize = mDeviceProfile.taskbarIconSize;
         } else {
             // widget_selection or shortcut_popup
             defaultIconSize = mDeviceProfile.iconSizePx;
         }
 
-        mCenterVertically = a.getBoolean(R.styleable.BubbleTextView_centerVertically, false);
 
         mIconSize = a.getDimensionPixelSize(R.styleable.BubbleTextView_iconSizeOverride,
                 defaultIconSize);
@@ -268,6 +269,10 @@
         mHideBadge = hideBadge;
     }
 
+    public void setSkipUserBadge(boolean skipUserBadge) {
+        mSkipUserBadge = skipUserBadge;
+    }
+
     /**
      * Resets the view so it can be recycled.
      */
@@ -279,15 +284,19 @@
         mDotParams.scale = 0f;
         mForceHideDot = false;
         setBackground(null);
-        if (FeatureFlags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) {
-            setMaxLines(1);
-        }
 
         setTag(null);
         if (mIconLoadRequest != null) {
             mIconLoadRequest.cancel();
             mIconLoadRequest = null;
         }
+        // Reset any shifty arrangements in case animation is disrupted.
+        setPivotY(0);
+        setAlpha(1);
+        setScaleY(1);
+        setTranslationY(0);
+        setMaxLines(1);
+        setVisibility(VISIBLE);
     }
 
     private void cancelDotScaleAnim() {
@@ -397,6 +406,9 @@
         if (mHideBadge || mDisplay == DISPLAY_SEARCH_RESULT_SMALL) {
             flags |= FLAG_NO_BADGE;
         }
+        if (mSkipUserBadge) {
+            flags |= FLAG_SKIP_USER_BADGE;
+        }
         FastBitmapDrawable iconDrawable = info.newIcon(getContext(), flags);
         mDotParams.appColor = iconDrawable.getIconColor();
         mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
@@ -410,11 +422,12 @@
     }
 
     /**
-     *  Only if actual text can be displayed in two line, the {@code true} value will be effective.
+     * Only if actual text can be displayed in two line, the {@code true} value will be effective.
      */
     protected boolean shouldUseTwoLine() {
-        return (FeatureFlags.enableTwolineAllapps() && isCurrentLanguageEnglish())
-                && (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW);
+        return isCurrentLanguageEnglish() && (mDisplay == DISPLAY_ALL_APPS
+                || mDisplay == DISPLAY_PREDICTION_ROW) && (Flags.enableTwolineToggle()
+                && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext()));
     }
 
     protected boolean isCurrentLanguageEnglish() {
@@ -422,8 +435,7 @@
     }
 
     @UiThread
-    @VisibleForTesting
-    public void applyLabel(ItemInfoWithIcon info) {
+    public void applyLabel(ItemInfo info) {
         CharSequence label = info.title;
         if (label != null) {
             mLastOriginalText = label;
@@ -546,9 +558,6 @@
     }
 
     private void checkForEllipsis() {
-        if (!ENABLE_ICON_LABEL_AUTO_SCALING.get()) {
-            return;
-        }
         float width = getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
         if (width <= 0) {
             return;
@@ -569,12 +578,12 @@
 
     /**
      * Find the appropriate text spacing to display the provided text
-     * @param paint the paint used by the text view
-     * @param text the text to display
-     * @param allowedWidthPx available space to render the text
-     * @param minSpacingEm minimum spacing allowed between characters
-     * @return the final textSpacing value
      *
+     * @param paint          the paint used by the text view
+     * @param text           the text to display
+     * @param allowedWidthPx available space to render the text
+     * @param minSpacingEm   minimum spacing allowed between characters
+     * @return the final textSpacing value
      * @see #setLetterSpacing(float)
      */
     private float findBestSpacingValue(TextPaint paint, String text, float allowedWidthPx,
@@ -802,13 +811,13 @@
      * iterating through the list of break points and determining if the strings between the break
      * points can fit within the line it is in. We will show the modified string if there is enough
      * horizontal and vertical space, otherwise this method will just return the original string.
-     *  Example assuming each character takes up one spot:
-     *  title = "Battery Stats", breakpoint = [6], stringPtr = 0, limitedWidth = 7
-     *  We get the current word -> from sublist(0, breakpoint[i]+1) so sublist (0,7) -> Battery,
-     *  now stringPtr = 7 then from sublist(7) the current string is " Stats" and the runningWidth
-     *  at this point exceeds limitedWidth and so we put " Stats" onto the next line (after checking
-     *  if the first char is a SPACE, we trim to append "Stats". So resulting string would be
-     *  "Battery\nStats"
+     * Example assuming each character takes up one spot:
+     * title = "Battery Stats", breakpoint = [6], stringPtr = 0, limitedWidth = 7
+     * We get the current word -> from sublist(0, breakpoint[i]+1) so sublist (0,7) -> Battery,
+     * now stringPtr = 7 then from sublist(7) the current string is " Stats" and the runningWidth
+     * at this point exceeds limitedWidth and so we put " Stats" onto the next line (after checking
+     * if the first char is a SPACE, we trim to append "Stats". So resulting string would be
+     * "Battery\nStats"
      */
     public static CharSequence modifyTitleToSupportMultiLine(int limitedWidth, int limitedHeight,
             CharSequence title, TextPaint paint, IntArray breakPoints, float spacingMultiplier,
@@ -820,28 +829,27 @@
         float currentWordWidth, runningWidth = 0;
         CharSequence currentWord;
         StringBuilder newString = new StringBuilder();
-        // TODO: Remove when ENABLE_ICON_LABEL_AUTO_SCALING feature flag is being cleaned up.
         paint.setLetterSpacing(MIN_LETTER_SPACING);
         int stringPtr = 0;
-        for (int i = 0; i < breakPoints.size()+1; i++) {
+        for (int i = 0; i < breakPoints.size() + 1; i++) {
             if (i < breakPoints.size()) {
-                currentWord = title.subSequence(stringPtr, breakPoints.get(i)+1);
+                currentWord = title.subSequence(stringPtr, breakPoints.get(i) + 1);
             } else {
                 // last word from recent breakpoint until the end of the string
                 currentWord = title.subSequence(stringPtr, title.length());
             }
-            currentWordWidth = paint.measureText(currentWord,0, currentWord.length());
+            currentWordWidth = paint.measureText(currentWord, 0, currentWord.length());
             runningWidth += currentWordWidth;
             if (runningWidth <= limitedWidth) {
                 newString.append(currentWord);
             } else {
-                if (i != 0)  {
+                if (i != 0) {
                     // If putting word onto a new line, make sure there is no space or new line
                     // character in the beginning of the current word and just put in the rest of
                     // the characters.
                     CharSequence lastCharacters = title.subSequence(stringPtr, title.length());
                     int beginningLetterType =
-                            Character.getType(Character.codePointAt(lastCharacters,0));
+                            Character.getType(Character.codePointAt(lastCharacters, 0));
                     if (beginningLetterType == Character.SPACE_SEPARATOR
                             || beginningLetterType == Character.LINE_SEPARATOR) {
                         lastCharacters = lastCharacters.length() > 1
@@ -862,7 +870,7 @@
                 // no need to look forward into the string if we've already finished processing
                 break;
             }
-            stringPtr = breakPoints.get(i)+1;
+            stringPtr = breakPoints.get(i) + 1;
         }
         return newString.toString();
     }
@@ -903,7 +911,8 @@
     /** Applies the given progress level to the this icon's progress bar. */
     @Nullable
     public PreloadIconDrawable applyProgressLevel() {
-        if (!(getTag() instanceof ItemInfoWithIcon)) {
+        if (!(getTag() instanceof ItemInfoWithIcon)
+                || ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
             return null;
         }
 
@@ -923,7 +932,7 @@
             if (mIcon instanceof PreloadIconDrawable) {
                 preloadIconDrawable = (PreloadIconDrawable) mIcon;
                 preloadIconDrawable.setLevel(progressLevel);
-                preloadIconDrawable.setIsDisabled(info.getProgressLevel() == 0);
+                preloadIconDrawable.setIsDisabled(isIconDisabled(info));
             } else {
                 preloadIconDrawable = makePreloadIcon();
                 setIcon(preloadIconDrawable);
@@ -948,10 +957,19 @@
         final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
 
         preloadDrawable.setLevel(progressLevel);
-        preloadDrawable.setIsDisabled(info.getProgressLevel() == 0);
+        preloadDrawable.setIsDisabled(isIconDisabled(info));
         return preloadDrawable;
     }
 
+    /**
+     * Returns true to grey the icon if the icon is either suspended or if the icon is pending
+     * download
+     */
+    public boolean isIconDisabled(ItemInfoWithIcon info) {
+        return info.isDisabled() || info.isPendingDownload();
+    }
+
+
     public void applyDotState(ItemInfo itemInfo, boolean animate) {
         if (mIcon instanceof FastBitmapDrawable) {
             boolean wasDotted = mDotInfo != null;
@@ -989,19 +1007,21 @@
     }
 
     private void setDownloadStateContentDescription(ItemInfoWithIcon info, int progressLevel) {
-        if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
+        if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_ARCHIVED) != 0 && progressLevel == 0) {
+            setContentDescription(getContext().getString(R.string.app_archived_title, info.title));
+        } else if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
                 != 0) {
             String percentageString = NumberFormat.getPercentInstance()
                     .format(progressLevel * 0.01);
             if ((info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
                 setContentDescription(getContext()
                         .getString(
-                            R.string.app_installing_title, info.title, percentageString));
+                                R.string.app_installing_title, info.title, percentageString));
             } else if ((info.runtimeStatusFlags
                     & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) {
                 setContentDescription(getContext()
                         .getString(
-                            R.string.app_downloading_title, info.title, percentageString));
+                                R.string.app_downloading_title, info.title, percentageString));
             }
         }
     }
@@ -1168,7 +1188,8 @@
     public SafeCloseable prepareDrawDragView() {
         resetIconScale();
         setForceHideDot(true);
-        return () -> { };
+        return () -> {
+        };
     }
 
     private void resetIconScale() {
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 5443ff9..72758f2 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -16,18 +16,12 @@
 
 package com.android.launcher3;
 
-import static android.animation.ValueAnimator.areAnimatorsEnabled;
-
-import static com.android.app.animation.Interpolators.DECELERATE_1_5;
-import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
-import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET;
 import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_PREVIEW_OFFSET;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -48,7 +42,6 @@
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
-import android.util.Property;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -71,6 +64,7 @@
 import com.android.launcher3.celllayout.ItemConfiguration;
 import com.android.launcher3.celllayout.ReorderAlgorithm;
 import com.android.launcher3.celllayout.ReorderParameters;
+import com.android.launcher3.celllayout.ReorderPreviewAnimation;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.folder.PreviewBackground;
@@ -189,7 +183,7 @@
 
     @ContainerType private final int mContainerType;
 
-    private final float mChildScale = 1f;
+    public static final float DEFAULT_SCALE = 1f;
 
     public static final int MODE_SHOW_REORDER_HINT = 0;
     public static final int MODE_DRAG_OVER = 1;
@@ -199,8 +193,8 @@
     private static final boolean DESTRUCTIVE_REORDER = false;
     private static final boolean DEBUG_VISUALIZE_OCCUPIED = false;
 
-    private static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
-    private static final int REORDER_ANIMATION_DURATION = 150;
+    public static final float REORDER_PREVIEW_MAGNITUDE = 0.12f;
+    public static final int REORDER_ANIMATION_DURATION = 150;
     @Thunk final float mReorderPreviewAnimationMagnitude;
 
     private final ArrayList<View> mIntersectingViews = new ArrayList<>();
@@ -219,6 +213,7 @@
     // Related to accessible drag and drop
     DragAndDropAccessibilityDelegate mTouchHelper;
 
+    CellLayoutContainer mCellLayoutContainer;
 
     public static final FloatProperty<CellLayout> SPRING_LOADED_PROGRESS =
             new FloatProperty<CellLayout>("spring_loaded_progress") {
@@ -233,8 +228,9 @@
                 }
             };
 
-    public CellLayout(Context context) {
-        this(context, null);
+    public CellLayout(Context context, CellLayoutContainer container) {
+        this(context, (AttributeSet) null);
+        this.mCellLayoutContainer = container;
     }
 
     public CellLayout(Context context, AttributeSet attrs) {
@@ -321,11 +317,18 @@
         addView(mShortcutsAndWidgets);
     }
 
+    public CellLayoutContainer getCellLayoutContainer() {
+        return mCellLayoutContainer;
+    }
+
+    public void setCellLayoutContainer(CellLayoutContainer cellLayoutContainer) {
+        mCellLayoutContainer = cellLayoutContainer;
+    }
+
     /**
      * Sets or clears a delegate used for accessible drag and drop
      */
     public void setDragAndDropAccessibilityDelegate(DragAndDropAccessibilityDelegate delegate) {
-        setOnClickListener(delegate);
         ViewCompat.setAccessibilityDelegate(this, delegate);
 
         mTouchHelper = delegate;
@@ -333,7 +336,6 @@
                 ? IMPORTANT_FOR_ACCESSIBILITY_YES : IMPORTANT_FOR_ACCESSIBILITY_NO;
         setImportantForAccessibility(accessibilityFlag);
         getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
-
         // ExploreByTouchHelper sets focusability. Clear it when the delegate is cleared.
         setFocusable(delegate != null);
         // Invalidate the accessibility hierarchy
@@ -578,9 +580,7 @@
     }
 
     protected void updateBgAlpha() {
-        if (!getWorkspace().mLauncher.isInState(EDIT_MODE)) {
-            mBackground.setAlpha((int) (mSpringLoadedProgress * 255));
-        }
+        mBackground.setAlpha((int) (mSpringLoadedProgress * 255));
     }
 
     /**
@@ -762,8 +762,8 @@
             bubbleChild.setTextVisibility(mContainerType != HOTSEAT);
         }
 
-        child.setScaleX(mChildScale);
-        child.setScaleY(mChildScale);
+        child.setScaleX(DEFAULT_SCALE);
+        child.setScaleY(DEFAULT_SCALE);
 
         // Generate an id for each view, this assumes we have at most 256x256 cells
         // per workspace screen
@@ -1192,7 +1192,7 @@
         // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable.
         View view = dragObject.dragView.getContentView();
         if (view instanceof LauncherAppWidgetHostView) {
-            int screenId = getWorkspace().getIdForScreen(this);
+            int screenId = mCellLayoutContainer.getCellLayoutId(this);
             cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect);
 
             ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, this, screenId);
@@ -1205,25 +1205,19 @@
             return getContext().getString(R.string.move_to_hotseat_position,
                     Math.max(cellX, cellY) + 1);
         } else {
-            Workspace<?> workspace = getWorkspace();
             int row = cellY + 1;
-            int col = workspace.mIsRtl ? mCountX - cellX : cellX + 1;
-            int panelCount = workspace.getPanelCount();
-            int screenId = workspace.getIdForScreen(this);
-            int pageIndex = workspace.getPageIndexForScreenId(screenId);
+            int col = Utilities.isRtl(getResources()) ? mCountX - cellX : cellX + 1;
+            int panelCount = mCellLayoutContainer.getPanelCount();
+            int pageIndex = mCellLayoutContainer.getCellLayoutIndex(this);
             if (panelCount > 1) {
                 // Increment the column if the target is on the right side of a two panel home
                 col += (pageIndex % panelCount) * mCountX;
             }
             return getContext().getString(R.string.move_to_empty_cell_description, row, col,
-                    workspace.getPageDescription(pageIndex));
+                    mCellLayoutContainer.getPageDescription(pageIndex));
         }
     }
 
-    private Workspace<?> getWorkspace() {
-        return Launcher.cast(mActivity).getWorkspace();
-    }
-
     public void clearDragOutlines() {
         final int oldIndex = mDragOutlineCurrent;
         mDragOutlineAnims[oldIndex].animateOut();
@@ -1439,174 +1433,14 @@
 
             CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
             if (c != null && !skip && (child instanceof Reorderable)) {
-                ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child,
-                        mode, lp.getCellX(), lp.getCellY(), c.cellX, c.cellY, c.spanX, c.spanY);
+                ReorderPreviewAnimation rha = new ReorderPreviewAnimation(child, mode,
+                        lp.getCellX(), lp.getCellY(), c.cellX, c.cellY, c.spanX, c.spanY,
+                        mReorderPreviewAnimationMagnitude, this, mShakeAnimators);
                 rha.animate();
             }
         }
     }
 
-    private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS =
-            new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") {
-                @Override
-                public Float get(ReorderPreviewAnimation anim) {
-                    return anim.animationProgress;
-                }
-
-                @Override
-                public void set(ReorderPreviewAnimation anim, Float progress) {
-                    anim.setAnimationProgress(progress);
-                }
-            };
-
-    // Class which represents the reorder preview animations. These animations show that an item is
-    // in a temporary state, and hint at where the item will return to.
-    class ReorderPreviewAnimation<T extends View & Reorderable> {
-        final T child;
-        float finalDeltaX;
-        float finalDeltaY;
-        float initDeltaX;
-        float initDeltaY;
-        final float finalScale;
-        float initScale;
-        final int mode;
-        boolean repeating = false;
-        private static final int PREVIEW_DURATION = 300;
-        private static final int HINT_DURATION = Workspace.REORDER_TIMEOUT;
-
-        private static final float CHILD_DIVIDEND = 4.0f;
-
-        public static final int MODE_HINT = 0;
-        public static final int MODE_PREVIEW = 1;
-
-        float animationProgress = 0;
-        ValueAnimator a;
-
-        ReorderPreviewAnimation(View childView, int mode, int cellX0, int cellY0,
-                int cellX1, int cellY1, int spanX, int spanY) {
-            regionToCenterPoint(cellX0, cellY0, spanX, spanY, mTmpPoint);
-            final int x0 = mTmpPoint[0];
-            final int y0 = mTmpPoint[1];
-            regionToCenterPoint(cellX1, cellY1, spanX, spanY, mTmpPoint);
-            final int x1 = mTmpPoint[0];
-            final int y1 = mTmpPoint[1];
-            final int dX = x1 - x0;
-            final int dY = y1 - y0;
-
-            this.child = (T) childView;
-            this.mode = mode;
-            finalDeltaX = 0;
-            finalDeltaY = 0;
-
-            MultiTranslateDelegate mtd = child.getTranslateDelegate();
-            initDeltaX = mtd.getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).getValue();
-            initDeltaY = mtd.getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).getValue();
-            initScale = child.getReorderBounceScale();
-            finalScale = mChildScale - (CHILD_DIVIDEND / child.getWidth()) * initScale;
-
-            int dir = mode == MODE_HINT ? -1 : 1;
-            if (dX == dY && dX == 0) {
-            } else {
-                if (dY == 0) {
-                    finalDeltaX = -dir * Math.signum(dX) * mReorderPreviewAnimationMagnitude;
-                } else if (dX == 0) {
-                    finalDeltaY = -dir * Math.signum(dY) * mReorderPreviewAnimationMagnitude;
-                } else {
-                    double angle = Math.atan( (float) (dY) / dX);
-                    finalDeltaX = (int) (-dir * Math.signum(dX)
-                            * Math.abs(Math.cos(angle) * mReorderPreviewAnimationMagnitude));
-                    finalDeltaY = (int) (-dir * Math.signum(dY)
-                            * Math.abs(Math.sin(angle) * mReorderPreviewAnimationMagnitude));
-                }
-            }
-        }
-
-        void setInitialAnimationValuesToBaseline() {
-            initScale = mChildScale;
-            initDeltaX = 0;
-            initDeltaY = 0;
-        }
-
-        void animate() {
-            boolean noMovement = (finalDeltaX == 0) && (finalDeltaY == 0);
-
-            if (mShakeAnimators.containsKey(child)) {
-                ReorderPreviewAnimation oldAnimation = mShakeAnimators.get(child);
-                mShakeAnimators.remove(child);
-
-                if (noMovement) {
-                    // A previous animation for this item exists, and no new animation will exist.
-                    // Finish the old animation smoothly.
-                    oldAnimation.finishAnimation();
-                    return;
-                } else {
-                    // A previous animation for this item exists, and a new one will exist. Stop
-                    // the old animation in its tracks, and proceed with the new one.
-                    oldAnimation.cancel();
-                }
-            }
-            if (noMovement) {
-                return;
-            }
-
-            ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
-            a = va;
-
-            // Animations are disabled in power save mode, causing the repeated animation to jump
-            // spastically between beginning and end states. Since this looks bad, we don't repeat
-            // the animation in power save mode.
-            if (areAnimatorsEnabled()) {
-                va.setRepeatMode(ValueAnimator.REVERSE);
-                va.setRepeatCount(ValueAnimator.INFINITE);
-            }
-
-            va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
-            va.setStartDelay((int) (Math.random() * 60));
-            va.addListener(new AnimatorListenerAdapter() {
-                public void onAnimationRepeat(Animator animation) {
-                    // We make sure to end only after a full period
-                    setInitialAnimationValuesToBaseline();
-                    repeating = true;
-                }
-            });
-            mShakeAnimators.put(child, this);
-            va.start();
-        }
-
-        private void setAnimationProgress(float progress) {
-            animationProgress = progress;
-            float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
-            float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
-            float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
-            child.getTranslateDelegate().setTranslation(INDEX_REORDER_BOUNCE_OFFSET, x, y);
-            float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
-            child.setReorderBounceScale(s);
-        }
-
-        private void cancel() {
-            if (a != null) {
-                a.cancel();
-            }
-        }
-
-        /**
-         * Smoothly returns the item to its baseline position / scale
-         */
-        @Thunk void finishAnimation() {
-            if (a != null) {
-                a.cancel();
-            }
-
-            setInitialAnimationValuesToBaseline();
-            ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS,
-                    animationProgress, 0);
-            a = va;
-            a.setInterpolator(DECELERATE_1_5);
-            a.setDuration(REORDER_ANIMATION_DURATION);
-            a.start();
-        }
-    }
-
     private void completeAndClearReorderPreviewAnimations() {
         for (ReorderPreviewAnimation a: mShakeAnimators.values()) {
             a.finishAnimation();
@@ -1617,7 +1451,7 @@
     private void commitTempPlacement(View dragView) {
         mTmpOccupied.copyTo(mOccupied);
 
-        int screenId = getWorkspace().getIdForScreen(this);
+        int screenId = mCellLayoutContainer.getCellLayoutId(this);
         int container = Favorites.CONTAINER_DESKTOP;
 
         if (mContainerType == HOTSEAT) {
@@ -1718,7 +1552,7 @@
 
         // First we determine if things have moved enough to cause a different layout
         ItemConfiguration swapSolution = findReorderSolution(pixelXY[0], pixelXY[1], spanX, spanY,
-                spanX,  spanY, direction, dragView,  true,  new ItemConfiguration());
+                spanX,  spanY, direction, dragView,  true);
 
         setUseTempCoords(true);
         if (swapSolution != null && swapSolution.isSolution) {
@@ -1747,13 +1581,13 @@
     }
 
     protected ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
-            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
-            ItemConfiguration solution) {
+            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX) {
         ItemConfiguration configuration = new ItemConfiguration();
         copyCurrentStateToSolution(configuration);
         ReorderParameters parameters = new ReorderParameters(pixelX, pixelY, spanX, spanY, minSpanX,
                 minSpanY, dragView, configuration);
-        return createReorderAlgorithm().findReorderSolution(parameters, decX);
+        int[] directionVector = direction != null ? direction : mDirectionVector;
+        return createReorderAlgorithm().findReorderSolution(parameters, directionVector, decX);
     }
 
     public void copyCurrentStateToSolution(ItemConfiguration solution) {
@@ -2077,7 +1911,7 @@
                 cellToPoint(cellX, cellY, cellPoint);
                 if (findReorderSolution(cellPoint[0], cellPoint[1], itemInfo.minSpanX,
                         itemInfo.minSpanY, itemInfo.spanX, itemInfo.spanY, mDirectionVector, null,
-                        true, new ItemConfiguration()).isSolution) {
+                        true).isSolution) {
                     return true;
                 }
             }
@@ -2092,9 +1926,18 @@
         int[] cellPoint = new int[2];
         int[] directionVector = new int[]{0, -1};
         cellToPoint(0, mCountY, cellPoint);
-        ItemConfiguration configuration = new ItemConfiguration();
-        if (findReorderSolution(cellPoint[0], cellPoint[1], mCountX, 1, mCountX, 1,
-                directionVector, null, false, configuration).isSolution) {
+        ItemConfiguration configuration = findReorderSolution(
+                cellPoint[0] /* pixelX */,
+                cellPoint[1] /* pixelY */,
+                mCountX /* minSpanX */,
+                1 /* minSpanY */,
+                mCountX /* spanX */,
+                1 /* spanY */,
+                directionVector /* direction */,
+                null /* dragView */,
+                false /* decX */
+        );
+        if (configuration.isSolution) {
             if (commitConfig) {
                 copySolutionToTempState(configuration, null);
                 commitTempPlacement(null);
diff --git a/src/com/android/launcher3/CellLayoutContainer.java b/src/com/android/launcher3/CellLayoutContainer.java
new file mode 100644
index 0000000..9ee0f70
--- /dev/null
+++ b/src/com/android/launcher3/CellLayoutContainer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+/**
+ * This interface should be implemented for any container/view that has a CellLayout as a children.
+ */
+public interface CellLayoutContainer {
+
+    /**
+     * Get the CellLayoutId for the given cellLayout.
+     */
+    int getCellLayoutId(CellLayout cellLayout);
+
+    /**
+     * Get the index of the given CellLayout out of all the other CellLayouts.
+     */
+    int getCellLayoutIndex(CellLayout cellLayout);
+
+    /**
+     * The total number of CellLayouts in the container.
+     */
+    int getPanelCount();
+
+    /**
+     * Used for accessibility, it returns the string that the assistant is going to say when
+     * referring to the given CellLayout.
+     */
+    String getPageDescription(int pageIndex);
+}
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 9a5627a..58789fd 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -27,7 +27,7 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -75,7 +75,7 @@
         }
 
         return (info instanceof LauncherAppWidgetInfo)
-                || (info instanceof FolderInfo);
+                || (info instanceof CollectionInfo);
     }
 
     @Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1ca7da9..a667c96 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -18,6 +18,7 @@
 
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT;
 import static com.android.launcher3.InvariantDeviceProfile.INDEX_LANDSCAPE;
 import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE;
@@ -46,6 +47,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.ResourcesCompat;
 
 import com.android.launcher3.CellLayout.ContainerType;
@@ -62,13 +64,13 @@
 import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType;
 import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
 import com.android.launcher3.responsive.ResponsiveSpecsProvider;
-import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.CellContentDimensions;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.IconSizeSteps;
 import com.android.launcher3.util.ResourceHelper;
 import com.android.launcher3.util.WindowBounds;
+import com.android.launcher3.util.window.WindowManagerProxy;
 
 import java.io.PrintWriter;
 import java.util.Locale;
@@ -78,10 +80,13 @@
 public class DeviceProfile {
 
     private static final int DEFAULT_DOT_SIZE = 100;
-    private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f;
     private static final float MIN_FOLDER_TEXT_SIZE_SP = 16f;
     private static final float MIN_WIDGET_PADDING_DP = 6f;
 
+    // Minimum aspect ratio beyond which an extra top padding may be applied to a bottom sheet.
+    private static final float MIN_ASPECT_RATIO_FOR_EXTRA_TOP_PADDING = 1.5f;
+    private static final float MAX_ASPECT_RATIO_FOR_ALTERNATE_EDIT_STATE = 1.5f;
+
     public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
     public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
     public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {
@@ -98,6 +103,7 @@
     public final boolean transposeLayoutWithOrientation;
     public final boolean isMultiDisplay;
     public final boolean isTwoPanels;
+    public boolean isPredictiveBackSwipe;
     public final boolean isQsbInline;
 
     // Device properties in current orientation
@@ -207,6 +213,8 @@
     // Hotseat
     public int numShownHotseatIcons;
     public int hotseatCellHeightPx;
+    private int mHotseatColumnSpan;
+    private int mHotseatWidthPx; // not used in vertical bar layout
     public final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
@@ -258,7 +266,6 @@
     public int overviewTaskIconSizePx;
     public int overviewTaskIconDrawableSizePx;
     public int overviewTaskIconDrawableSizeGridPx;
-    public int overviewTaskIconAppChipMenuDrawableSizePx;
     public int overviewTaskThumbnailTopMarginPx;
     public final int overviewActionsHeight;
     public final int overviewActionsTopMarginPx;
@@ -346,7 +353,8 @@
         isTablet = info.isTablet(windowBounds);
         isPhone = !isTablet;
         isTwoPanels = isTablet && isMultiDisplay;
-        isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS;
+        isTaskbarPresent = isTablet
+                && WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess();
 
         // Some more constants.
         context = getContext(context, info, isVerticalBarLayout() || (isTablet && isLandscape)
@@ -415,9 +423,18 @@
         gridVisualizationPaddingY = res.getDimensionPixelSize(
                 R.dimen.grid_visualization_vertical_cell_spacing);
 
-        bottomSheetTopPadding = mInsets.top // statusbar height
-                + res.getDimensionPixelSize(R.dimen.bottom_sheet_extra_top_padding)
-                + (isTablet ? 0 : edgeMarginPx); // phones need edgeMarginPx additional padding
+        {
+            // In large screens, in portrait mode, a bottom sheet can appear too elongated, so, we
+            // apply additional padding.
+            final boolean applyExtraTopPadding = isTablet
+                    && !isLandscape
+                    && (aspectRatio > MIN_ASPECT_RATIO_FOR_EXTRA_TOP_PADDING);
+            final int derivedTopPadding = heightPx / 6;
+            bottomSheetTopPadding = mInsets.top // statusbar height
+                    + (applyExtraTopPadding ? derivedTopPadding : 0)
+                    + (isTablet ? 0 : edgeMarginPx); // phones need edgeMarginPx additional padding
+        }
+
         bottomSheetOpenDuration = res.getInteger(R.integer.config_bottomSheetOpenDuration);
         bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration);
         if (isTablet) {
@@ -425,7 +442,11 @@
             if (isMultiDisplay && !ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH.get()) {
                 // TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth
                 // when screen recorder bug is fixed.
-                bottomSheetDepth = 1f;
+                if (enableScalingRevealHomeAnimation()) {
+                    bottomSheetDepth = 0.3f;
+                } else {
+                    bottomSheetDepth = 1f;
+                }
             } else {
                 // The goal is to set wallpaper to zoom at workspaceContentScale when in AllApps.
                 // When depth is 0, wallpaper zoom is set to maxWallpaperScale.
@@ -493,8 +514,17 @@
         }
 
         dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
-        dropTargetBarTopMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_top_margin);
-        dropTargetBarBottomMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_bottom_margin);
+        // Some foldable portrait modes are too wide in terms of aspect ratio so we need to tweak
+        // the dimensions for edit state.
+        final boolean shouldApplyWidePortraitDimens = isTablet
+                && !isLandscape
+                && aspectRatio < MAX_ASPECT_RATIO_FOR_ALTERNATE_EDIT_STATE;
+        dropTargetBarTopMarginPx = shouldApplyWidePortraitDimens
+                ? 0
+                : res.getDimensionPixelSize(R.dimen.drop_target_top_margin);
+        dropTargetBarBottomMarginPx = shouldApplyWidePortraitDimens
+                ? res.getDimensionPixelSize(R.dimen.drop_target_bottom_margin_wide_portrait)
+                : res.getDimensionPixelSize(R.dimen.drop_target_bottom_margin);
         dropTargetDragPaddingPx = res.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
         dropTargetTextSizePx = res.getDimensionPixelSize(R.dimen.drop_target_text_size);
         dropTargetHorizontalPaddingPx = res.getDimensionPixelSize(
@@ -524,6 +554,7 @@
         areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         numShownHotseatIcons =
                 isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        mHotseatColumnSpan = inv.numColumns;
 
         numShownAllAppsColumns =
                 isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
@@ -585,8 +616,9 @@
             }
         }
 
-        springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize(
-                R.dimen.spring_loaded_hotseat_top_margin);
+        springLoadedHotseatBarTopMarginPx = shouldApplyWidePortraitDimens
+                ? res.getDimensionPixelSize(R.dimen.spring_loaded_hotseat_top_margin_wide_portrait)
+                : res.getDimensionPixelSize(R.dimen.spring_loaded_hotseat_top_margin);
 
         if (mIsResponsiveGrid) {
             updateHotseatSizes(mResponsiveWorkspaceCellSpec.getIconSize());
@@ -641,8 +673,8 @@
                     DimensionType.WIDTH, numShownAllAppsColumns, availableWidthPx,
                     mResponsiveWorkspaceWidthSpec);
             mResponsiveAllAppsHeightSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio,
-                    DimensionType.HEIGHT, inv.numRows,  heightPx - mInsets.top,
-                    mResponsiveWorkspaceHeightSpec);
+                    DimensionType.HEIGHT, inv.numAllAppsRowsForCellHeightCalculation,
+                    heightPx - mInsets.top, mResponsiveWorkspaceHeightSpec);
 
             ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create(
                     new ResourceHelper(context,
@@ -678,8 +710,6 @@
                 res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size);
         overviewTaskIconDrawableSizeGridPx =
                 res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_drawable_size_grid);
-        overviewTaskIconAppChipMenuDrawableSizePx = res.getDimensionPixelSize(
-                R.dimen.task_thumbnail_icon_menu_drawable_size);
         overviewTaskThumbnailTopMarginPx =
                 enableOverviewIconMenu() ? 0 : overviewTaskIconSizePx + overviewTaskMarginPx;
         // Don't add margin with floating search bar to minimize risk of overlapping.
@@ -709,7 +739,7 @@
         }
 
         // Calculate all of the remaining variables.
-        extraSpace = updateAvailableDimensions(res);
+        extraSpace = updateAvailableDimensions(context);
 
         calculateAndSetWorkspaceVerticalPadding(context, inv, extraSpace);
 
@@ -734,14 +764,9 @@
             hotseatBorderSpace = cellLayoutBorderSpacePx.y;
         }
 
-        // AllApps height calculation depends on updated cellSize
         if (isTablet) {
-            int collapseHandleHeight =
-                    res.getDimensionPixelOffset(R.dimen.bottom_sheet_handle_area_height);
-            int contentHeight = heightPx - collapseHandleHeight - hotseatQsbHeight;
-            int targetContentHeight = (int) (allAppsCellHeightPx * ALL_APPS_TABLET_MAX_ROWS);
-            allAppsPadding.top = Math.max(mInsets.top, contentHeight - targetContentHeight);
-            allAppsShiftRange = heightPx - allAppsPadding.top;
+            allAppsPadding.top = mInsets.top;
+            allAppsShiftRange = heightPx;
         } else {
             allAppsPadding.top = 0;
             allAppsShiftRange =
@@ -789,14 +814,15 @@
      * width of the hotseat.
      */
     private int calculateQsbWidth(int hotseatBorderSpace) {
+        int iconExtraSpacePx = iconSizePx - getIconVisibleSizePx(iconSizePx);
         if (isQsbInline) {
             int columns = getPanelCount() * inv.numColumns;
             return getIconToIconWidthForColumns(columns)
                     - iconSizePx * numShownHotseatIcons
-                    - hotseatBorderSpace * numShownHotseatIcons;
+                    - hotseatBorderSpace * numShownHotseatIcons
+                    - iconExtraSpacePx;
         } else {
-            int columns = inv.hotseatColumnSpan[mTypeIndex];
-            return getIconToIconWidthForColumns(columns);
+            return getIconToIconWidthForColumns(mHotseatColumnSpan) - iconExtraSpacePx;
         }
     }
 
@@ -867,10 +893,31 @@
     public void recalculateHotseatWidthAndBorderSpace() {
         if (!mIsScalableGrid) return;
 
-        int columns = inv.hotseatColumnSpan[mTypeIndex];
-        float hotseatWidthPx = getIconToIconWidthForColumns(columns);
-        hotseatBorderSpace = calculateHotseatBorderSpace(hotseatWidthPx, /* numExtraBorder= */ 0);
+        updateHotseatWidthAndBorderSpace(inv.numColumns);
+        int numWorkspaceColumns = getPanelCount() * inv.numColumns;
+        if (isTwoPanels) {
+            updateHotseatWidthAndBorderSpace(inv.numDatabaseHotseatIcons);
+            // If hotseat doesn't fit with current width, increase column span to fit by multiple
+            // of 2.
+            while (hotseatBorderSpace < mMinHotseatIconSpacePx
+                    && mHotseatColumnSpan < numWorkspaceColumns) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan + 2);
+            }
+        }
+        if (isQsbInline) {
+            // If QSB is inline, reduce column span until it fits.
+            int maxHotseatWidthAllowedPx = getIconToIconWidthForColumns(numWorkspaceColumns);
+            int minHotseatWidthRequiredPx =
+                    mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            while (minHotseatWidthRequiredPx > maxHotseatWidthAllowedPx
+                    && mHotseatColumnSpan > 1) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan - 1);
+                minHotseatWidthRequiredPx =
+                        mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            }
+        }
         hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace);
+
         // Spaces should be correct when the nav buttons are not inline
         if (!areNavButtonsInline) {
             return;
@@ -912,6 +959,12 @@
         } while (hotseatBorderSpace < mMinHotseatIconSpacePx && numShownHotseatIcons > 1);
     }
 
+    private void updateHotseatWidthAndBorderSpace(int columns) {
+        mHotseatColumnSpan = columns;
+        mHotseatWidthPx = getIconToIconWidthForColumns(mHotseatColumnSpan);
+        hotseatBorderSpace = calculateHotseatBorderSpace(mHotseatWidthPx, /* numExtraBorder= */ 0);
+    }
+
     private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) {
         return getCellLayoutBorderSpace(idp, 1f);
     }
@@ -935,6 +988,16 @@
         return mInfo;
     }
 
+    @VisibleForTesting
+    public int getHotseatColumnSpan() {
+        return mHotseatColumnSpan;
+    }
+
+    @VisibleForTesting
+    public int getHotseatWidthPx() {
+        return mHotseatWidthPx;
+    }
+
     public Builder toBuilder(Context context) {
         WindowBounds bounds = new WindowBounds(
                 widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
@@ -992,16 +1055,6 @@
         float workspaceCellPaddingY = getCellSize().y - iconSizePx - iconDrawablePaddingPx
                 - iconTextHeight;
 
-        if (mIsResponsiveGrid) {
-            iconTextSizePx = 0;
-            iconDrawablePaddingPx = 0;
-            int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
-            cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
-            autoResizeAllAppsCells();
-
-            return;
-        }
-
         // We want enough space so that the text is closer to its corresponding icon.
         if (workspaceCellPaddingY < iconTextHeight) {
             iconTextSizePx = 0;
@@ -1014,14 +1067,14 @@
     /**
      * Returns the amount of extra (or unused) vertical space.
      */
-    private int updateAvailableDimensions(Resources res) {
-        iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid;
+    private int updateAvailableDimensions(Context context) {
+        iconCenterVertically = (mIsScalableGrid || mIsResponsiveGrid) && isVerticalBarLayout();
 
         if (mIsResponsiveGrid) {
             iconSizePx = mResponsiveWorkspaceCellSpec.getIconSize();
             iconTextSizePx = mResponsiveWorkspaceCellSpec.getIconTextSize();
             mIconDrawablePaddingOriginalPx = mResponsiveWorkspaceCellSpec.getIconDrawablePadding();
-            updateIconSize(1f, res);
+            updateIconSize(1f, context);
             updateWorkspacePadding();
             return 0;
         }
@@ -1031,7 +1084,7 @@
         iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics));
         iconTextSizePx = pxFromSp(invIconTextSizeSp, mMetrics);
 
-        updateIconSize(1f, res);
+        updateIconSize(1f, context);
         updateWorkspacePadding();
 
         // Check to see if the icons fit within the available height.
@@ -1055,7 +1108,7 @@
 
         if (shouldScale) {
             float scale = Math.min(scaleX, scaleY);
-            updateIconSize(scale, res);
+            updateIconSize(scale, context);
             extraHeight = Math.max(0, maxHeight - getCellLayoutHeightSpecification());
         }
 
@@ -1074,11 +1127,8 @@
     }
 
     private int getNormalizedIconDrawablePadding(int iconSizePx, int iconDrawablePadding) {
-        // TODO(b/235886078): workaround needed because of this bug
-        // Icons are 10% larger on XML than their visual size,
-        // so remove that extra space to get labels closer to the correct padding
-        int iconVisibleSizePx = Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
-        return Math.max(0, iconDrawablePadding - ((iconSizePx - iconVisibleSizePx) / 2));
+        return Math.max(0, iconDrawablePadding
+                - ((iconSizePx - getIconVisibleSizePx(iconSizePx)) / 2));
     }
 
     private int getNormalizedIconDrawablePadding() {
@@ -1091,8 +1141,7 @@
         // so remove that extra space to get labels closer to the correct padding
         int drawablePadding = (folderCellHeightPx - folderChildIconSizePx - textHeight) / 3;
 
-        int iconVisibleSizePx = Math.round(ICON_VISIBLE_AREA_FACTOR * folderChildIconSizePx);
-        int iconSizeDiff = folderChildIconSizePx - iconVisibleSizePx;
+        int iconSizeDiff = folderChildIconSizePx - getIconVisibleSizePx(folderChildIconSizePx);
         return Math.max(0, drawablePadding - iconSizeDiff / 2);
     }
 
@@ -1105,7 +1154,7 @@
      * iconTextSizePx, iconDrawablePaddingPx, cellWidth/Height, allApps* variants,
      * hotseat sizes, workspaceSpringLoadedShrinkFactor, folderIconSizePx, and folderIconOffsetYPx.
      */
-    public void updateIconSize(float scale, Resources res) {
+    public void updateIconSize(float scale, Context context) {
         // Icon scale should never exceed 1, otherwise pixellation may occur.
         iconScale = Math.min(1f, scale);
         cellScaleToFit = scale;
@@ -1123,25 +1172,28 @@
                 iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
             }
 
-            iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+            if (isVerticalLayout) {
+                iconDrawablePaddingPx = 0;
+                iconTextSizePx = 0;
+            } else {
+                iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+            }
 
             CellContentDimensions cellContentDimensions = new CellContentDimensions(iconSizePx,
                     iconDrawablePaddingPx,
                     iconTextSizePx);
-            if (isVerticalLayout) {
-                if (cellHeightPx < iconSizePx) {
-                    cellContentDimensions.setIconSizePx(
-                            mIconSizeSteps.getIconSmallerThan(cellHeightPx));
-                }
-            } else {
-                cellContentDimensions.resizeToFitCellHeight(cellHeightPx, mIconSizeSteps);
-            }
+            int cellContentHeight = cellContentDimensions.resizeToFitCellHeight(cellHeightPx,
+                    mIconSizeSteps);
             iconSizePx = cellContentDimensions.getIconSizePx();
             iconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
             iconTextSizePx = cellContentDimensions.getIconTextSizePx();
-            int cellContentHeight = cellContentDimensions.getCellContentHeight();
 
-            cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
+            if (isVerticalLayout) {
+                cellYPaddingPx = Math.max(0, getCellSize().y - getIconSizeWithOverlap(iconSizePx))
+                        / 2;
+            } else {
+                cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
+            }
         } else if (mIsScalableGrid) {
             iconDrawablePaddingPx = (int) (getNormalizedIconDrawablePadding() * iconScale);
             cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale);
@@ -1222,13 +1274,14 @@
         if (mIsResponsiveGrid) {
             updateAllAppsWithResponsiveMeasures();
         } else {
-            updateAllAppsIconSize(scale, res);
+            updateAllAppsIconSize(scale, context.getResources());
         }
         updateAllAppsContainerWidth();
-        if (isVerticalBarLayout()) {
+        if (isVerticalLayout && !mIsResponsiveGrid) {
             hideWorkspaceLabelsIfNotEnoughSpace();
         }
-        if (FeatureFlags.enableTwolineAllapps()) {
+        if ((Flags.enableTwolineToggle()
+                && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(context))) {
             // Add extra textHeight to the existing allAppsCellHeight.
             allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
         }
@@ -1349,7 +1402,7 @@
 
         if (allAppsCellHeightPx < cellContentDimensions.getCellContentHeight()) {
             if (isVerticalBarLayout()) {
-                if (allAppsCellHeightPx < iconSizePx) {
+                if (allAppsCellHeightPx < allAppsIconSizePx) {
                     cellContentDimensions.setIconSizePx(
                             mIconSizeSteps.getIconSmallerThan(allAppsCellHeightPx));
                 }
@@ -1363,6 +1416,10 @@
         }
 
         allAppsCellHeightPx += mResponsiveAllAppsHeightSpec.getGutterPx();
+
+        if (isVerticalBarLayout()) {
+            autoResizeAllAppsCells();
+        }
     }
 
     /**
@@ -1740,15 +1797,8 @@
             // The hotseat icons will be placed in the middle of the hotseat cells.
             // Changing the hotseatCellHeightPx is not affecting hotseat icon positions
             // in vertical bar layout.
-            // Workspace icons are moved up by a small factor. The variable diffOverlapFactor
-            // is set to account for that difference.
-            float diffOverlapFactor = mIsResponsiveGrid ? 0
-                    : iconSizePx * (ICON_OVERLAP_FACTOR - 1) / 2;
-
-            int paddingTop = Math.max((int) (mInsets.top + cellLayoutPaddingPx.top
-                    - diffOverlapFactor), 0);
-            int paddingBottom = Math.max((int) (mInsets.bottom + cellLayoutPaddingPx.bottom
-                    + diffOverlapFactor), 0);
+            int paddingTop = Math.max((int) (mInsets.top + cellLayoutPaddingPx.top), 0);
+            int paddingBottom = Math.max((int) (mInsets.bottom + cellLayoutPaddingPx.bottom), 0);
 
             if (isSeascape()) {
                 hotseatBarPadding.set(mInsets.left + mHotseatBarEdgePaddingPx, paddingTop,
@@ -1788,7 +1838,8 @@
             }
 
         } else if (mIsScalableGrid) {
-            int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2;
+            int iconExtraSpacePx = iconSizePx - getIconVisibleSizePx(iconSizePx);
+            int sideSpacing = (availableWidthPx - (hotseatQsbWidth + iconExtraSpacePx)) / 2;
             hotseatBarPadding.set(sideSpacing,
                     0,
                     sideSpacing,
@@ -1827,13 +1878,24 @@
                 availableWidthPx - allAppsSpacing,
                 0 /* borderSpace */,
                 numShownAllAppsColumns);
-        int iconVisibleSize = Math.round(ICON_VISIBLE_AREA_FACTOR * allAppsIconSizePx);
-        int iconAlignmentMargin = (cellWidth - iconVisibleSize) / 2;
+        int iconAlignmentMargin = (cellWidth - getIconVisibleSizePx(allAppsIconSizePx)) / 2;
 
         return (Utilities.isRtl(context.getResources()) ? allAppsPadding.right
                 : allAppsPadding.left) + iconAlignmentMargin;
     }
 
+    /**
+     * TODO(b/235886078): workaround needed because of this bug
+     * Icons are 10% larger on XML than their visual size, so remove that extra space to get
+     * some dimensions correct.
+     *
+     * When this bug is resolved this method will no longer be needed and we would be able to
+     * replace all instances where this method is called with iconSizePx.
+     */
+    private int getIconVisibleSizePx(int iconSizePx) {
+        return Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
+    }
+
     private int getAdditionalQsbSpace() {
         return isQsbInline ? hotseatQsbWidth + hotseatBorderSpace : 0;
     }
@@ -2098,7 +2160,8 @@
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
-        writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
+        writer.println(prefix + "\tmHotseatColumnSpan: " + mHotseatColumnSpan);
+        writer.println(prefix + pxToDpStr("mHotseatWidthPx", mHotseatWidthPx));
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
         writer.println(prefix + pxToDpStr("hotseatBarBottomSpacePx", hotseatBarBottomSpacePx));
         writer.println(prefix + pxToDpStr("mHotseatBarEdgePaddingPx",
@@ -2153,8 +2216,6 @@
                 overviewTaskIconDrawableSizePx));
         writer.println(prefix + pxToDpStr("overviewTaskIconDrawableSizeGridPx",
                 overviewTaskIconDrawableSizeGridPx));
-        writer.println(prefix + pxToDpStr("overviewTaskIconAppChipMenuDrawableSizePx",
-                overviewTaskIconAppChipMenuDrawableSizePx));
         writer.println(prefix + pxToDpStr("overviewTaskThumbnailTopMarginPx",
                 overviewTaskThumbnailTopMarginPx));
         writer.println(prefix + pxToDpStr("overviewActionsTopMarginPx",
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index ec26f58..fe9348c 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3;
 
-import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW;
-
 import android.content.Context;
 import android.graphics.Rect;
 import android.text.TextUtils;
@@ -93,7 +91,6 @@
      * @return true if the keyboard is shown correctly and focus is given to this view.
      */
     public boolean showKeyboard() {
-        onKeyboardShown();
         return requestFocus() && showSoftInputInternal();
     }
 
@@ -120,11 +117,6 @@
         }
     }
 
-    protected void onKeyboardShown() {
-        ActivityContext.lookupContext(getContext()).getStatsLogManager()
-                .keyboardStateManager().setKeyboardState(SHOW);
-    }
-
     private boolean showSoftInputInternal() {
         boolean result = false;
         InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index a13dcc1..eff748a 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -155,7 +155,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      * <p>Override in each subclass of this base class.
      */
-    public abstract String scrollToPositionAtProgress(float touchFraction);
+    public abstract CharSequence scrollToPositionAtProgress(float touchFraction);
 
     /**
      * Updates the bounds for the scrollbar.
@@ -193,15 +193,4 @@
         }
         scrollToPosition(0);
     }
-
-    /**
-     * Scrolls this recycler view to the bottom with easing and duration.
-     */
-    public void scrollToBottomWithMotion() {
-        if (mScrollbar != null) {
-            mScrollbar.reattachThumbToScroll();
-        }
-        // Emphasized interpolators with 500ms duration
-        smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, 500);
-    }
 }
diff --git a/src/com/android/launcher3/GestureNavContract.java b/src/com/android/launcher3/GestureNavContract.java
index c782dca..9ef6edc 100644
--- a/src/com/android/launcher3/GestureNavContract.java
+++ b/src/com/android/launcher3/GestureNavContract.java
@@ -20,11 +20,9 @@
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
 
-import android.annotation.TargetApi;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.RectF;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -69,7 +67,6 @@
     /**
      * Sends the position information to the receiver
      */
-    @TargetApi(Build.VERSION_CODES.R)
     public void sendEndPosition(RectF position, ActivityContext context,
             @Nullable SurfaceControl surfaceControl) {
         Bundle result = new Bundle();
@@ -95,9 +92,6 @@
      * Clears and returns the GestureNavContract if it was present in the intent.
      */
     public static GestureNavContract fromIntent(Intent intent) {
-        if (!Utilities.ATLEAST_R) {
-            return null;
-        }
         Bundle extras = intent.getBundleExtra(EXTRA_GESTURE_CONTRACT);
         if (extras == null) {
             return null;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 3b12b86..37737d8 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -207,6 +207,7 @@
 
     public void setWorkspace(Workspace<?> w) {
         mWorkspace = w;
+        setCellLayoutContainer(w);
     }
 
     @Override
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 5721ed3..f405b93 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.util.LockedUserState;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Partner;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.WindowManagerProxy;
 
@@ -72,9 +73,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
-public class InvariantDeviceProfile {
+public class InvariantDeviceProfile implements SafeCloseable {
 
     public static final String TAG = "IDP";
     // We do not need any synchronization for this variable as its only written on UI thread.
@@ -162,7 +164,6 @@
      */
     public int numDatabaseHotseatIcons;
 
-    public int[] hotseatColumnSpan;
     public float[] hotseatBarBottomSpace;
     public float[] hotseatQsbSpace;
 
@@ -170,6 +171,7 @@
      * Number of columns in the all apps list.
      */
     public int numAllAppsColumns;
+    public int numAllAppsRowsForCellHeightCalculation;
     public int numDatabaseAllAppsColumns;
     public @StyleRes int allAppsStyle;
 
@@ -228,9 +230,8 @@
         if (!newGridName.equals(gridName)) {
             LauncherPrefs.get(context).put(GRID_NAME, newGridName);
         }
-        LockedUserState.get(context).runOnUserUnlocked(() -> {
-            new DeviceGridState(this).writeToPrefs(context);
-        });
+        LockedUserState.get(context).runOnUserUnlocked(() ->
+            new DeviceGridState(this).writeToPrefs(context));
 
         DisplayController.INSTANCE.get(context).setPriorityListener(
                 (displayContext, info, flags) -> {
@@ -247,7 +248,7 @@
     public InvariantDeviceProfile(Context context, String gridName) {
         String newName = initGrid(context, gridName);
         if (newName == null || !newName.equals(gridName)) {
-            throw new IllegalArgumentException("Unknown grid name");
+            throw new IllegalArgumentException("Unknown grid name: " + gridName);
         }
     }
 
@@ -261,7 +262,7 @@
 
         // Get the display info based on default display and interpolate it to existing display
         Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
-        @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
+        @DeviceType int defaultDeviceType = defaultInfo.getDeviceType();
         DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
                 defaultInfo,
                 getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
@@ -270,7 +271,7 @@
 
         Context displayContext = context.createDisplayContext(display);
         Info myInfo = new Info(displayContext);
-        @DeviceType int deviceType = getDeviceType(myInfo);
+        @DeviceType int deviceType = myInfo.getDeviceType();
         DisplayOption myDisplayOption = invDistWeightedInterpolate(
                 myInfo,
                 getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -294,6 +295,11 @@
         initGrid(context, myInfo, result, deviceType);
     }
 
+    @Override
+    public void close() {
+        DisplayController.INSTANCE.executeIfCreated(dc -> dc.setPriorityListener(null));
+    }
+
     /**
      * Reinitialize the current grid after a restore, where some grids might now be disabled.
      */
@@ -323,30 +329,13 @@
         }
     }
 
-    private static @DeviceType int getDeviceType(Info displayInfo) {
-        int flagPhone = 1 << 0;
-        int flagTablet = 1 << 1;
-
-        int type = displayInfo.supportedBounds.stream()
-                .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
-                .reduce(0, (a, b) -> a | b);
-        if (type == (flagPhone | flagTablet)) {
-            // device has profiles supporting both phone and table modes
-            return TYPE_MULTI_DISPLAY;
-        } else if (type == flagTablet) {
-            return TYPE_TABLET;
-        } else {
-            return TYPE_PHONE;
-        }
-    }
-
     public static String getCurrentGridName(Context context) {
         return LauncherPrefs.get(context).get(GRID_NAME);
     }
 
     private String initGrid(Context context, String gridName) {
         Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
-        @DeviceType int deviceType = getDeviceType(displayInfo);
+        @DeviceType int deviceType = displayInfo.getDeviceType();
 
         ArrayList<DisplayOption> allOptions =
                 getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -357,6 +346,15 @@
         return displayOption.grid.name;
     }
 
+    /**
+     * @deprecated This is a temporary solution because on the backup and restore case we modify the
+     * IDP, this resets it. b/332974074
+     */
+    @Deprecated
+    public void reset(Context context) {
+        initGrid(context, getCurrentGridName(context));
+    }
+
     @VisibleForTesting
     public static String getDefaultGridName(Context context) {
         return new InvariantDeviceProfile().initGrid(context, null);
@@ -393,6 +391,8 @@
         workspaceCellSpecsTwoPanelId = closestProfile.mWorkspaceCellSpecsTwoPanelId;
         allAppsCellSpecsId = closestProfile.mAllAppsCellSpecsId;
         allAppsCellSpecsTwoPanelId = closestProfile.mAllAppsCellSpecsTwoPanelId;
+        numAllAppsRowsForCellHeightCalculation =
+                closestProfile.mNumAllAppsRowsForCellHeightCalculation;
         this.deviceType = deviceType;
 
         inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -416,13 +416,13 @@
         numShownHotseatIcons = closestProfile.numHotseatIcons;
         numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
-        hotseatColumnSpan = closestProfile.hotseatColumnSpan;
         hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace;
         hotseatQsbSpace = displayOption.hotseatQsbSpace;
 
         allAppsStyle = closestProfile.allAppsStyle;
 
         numAllAppsColumns = closestProfile.numAllAppsColumns;
+
         numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseAllAppsColumns : closestProfile.numAllAppsColumns;
 
@@ -574,6 +574,45 @@
     }
 
     /**
+     * Returns the GridOption associated to the given file name or null if the fileName is not
+     * supported.
+     * Ej, launcher.db -> "normal grid", launcher_4_by_4.db -> "practical grid"
+     */
+    public GridOption getGridOptionFromFileName(Context context, String fileName) {
+        return parseAllGridOptions(context).stream()
+                .filter(gridOption -> Objects.equals(gridOption.dbFile, fileName))
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * Returns the name of the given size on the current device or empty string if the size is not
+     * supported. Ej. 4x4 -> normal, 5x4 -> practical, etc.
+     * (Note: the name of the grid can be different for the same grid size depending of
+     * the values of the InvariantDeviceProfile)
+     *
+     */
+    public String getGridNameFromSize(Context context, Point size) {
+        return parseAllGridOptions(context).stream()
+                .filter(gridOption -> gridOption.numColumns == size.x
+                        && gridOption.numRows == size.y)
+                .map(gridOption -> gridOption.name)
+                .findFirst()
+                .orElse("");
+    }
+
+    /**
+     * Returns the grid option for the given gridName on the current device (Note: the gridOption
+     * be different for the same gridName depending on the values of the InvariantDeviceProfile).
+     */
+    public GridOption getGridOptionFromName(Context context, String gridName) {
+        return parseAllGridOptions(context).stream()
+                .filter(gridOption -> Objects.equals(gridOption.name, gridName))
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
      * @return all the grid options that can be shown on the device
      */
     public List<GridOption> parseAllGridOptions(Context context) {
@@ -821,12 +860,11 @@
 
         private final @StyleRes int allAppsStyle;
         private final int numAllAppsColumns;
+        private final int mNumAllAppsRowsForCellHeightCalculation;
         private final int numDatabaseAllAppsColumns;
         private final int numHotseatIcons;
         private final int numDatabaseHotseatIcons;
 
-        private final int[] hotseatColumnSpan = new int[COUNT_SIZES];
-
         private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
 
         private @DimenRes int inlineNavButtonsEndSpacing;
@@ -877,17 +915,6 @@
             numDatabaseHotseatIcons = a.getInt(
                     R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
 
-            hotseatColumnSpan[INDEX_DEFAULT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpan, numColumns);
-            hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanLandscape, numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelLandscape,
-                    numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelPortrait,
-                    numColumns);
-
             inlineNavButtonsEndSpacing =
                     a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
                             R.dimen.taskbar_button_margin_default);
@@ -943,34 +970,37 @@
                         R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
                 mWorkspaceSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_workspaceSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mWorkspaceSpecsId);
                 mAllAppsSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_allAppsSpecsId, INVALID_RESOURCE_HANDLE);
                 mAllAppsSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_allAppsSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mAllAppsSpecsId);
                 mFolderSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_folderSpecsId, INVALID_RESOURCE_HANDLE);
                 mFolderSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_folderSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mFolderSpecsId);
                 mHotseatSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_hotseatSpecsId, INVALID_RESOURCE_HANDLE);
                 mHotseatSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_hotseatSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mHotseatSpecsId);
                 mWorkspaceCellSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_workspaceCellSpecsId,
                         INVALID_RESOURCE_HANDLE);
                 mWorkspaceCellSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_workspaceCellSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mWorkspaceCellSpecsId);
                 mAllAppsCellSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_allAppsCellSpecsId,
                         INVALID_RESOURCE_HANDLE);
                 mAllAppsCellSpecsTwoPanelId = a.getResourceId(
                         R.styleable.GridDisplayOption_allAppsCellSpecsTwoPanelId,
-                        INVALID_RESOURCE_HANDLE);
+                        mAllAppsCellSpecsId);
+                mNumAllAppsRowsForCellHeightCalculation = a.getInt(
+                        R.styleable.GridDisplayOption_numAllAppsRowsForCellHeightCalculation,
+                        numRows);
             } else {
                 mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
                 mWorkspaceSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
@@ -984,6 +1014,7 @@
                 mWorkspaceCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
                 mAllAppsCellSpecsId = INVALID_RESOURCE_HANDLE;
                 mAllAppsCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+                mNumAllAppsRowsForCellHeightCalculation = numRows;
             }
 
             int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e41a8a5..dc7c349 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,6 +19,7 @@
 import static android.app.PendingIntent.FLAG_IMMUTABLE;
 import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
@@ -26,6 +27,8 @@
 import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
+import static com.android.launcher3.Flags.enableAddAppWidgetViaConfigActivityV2;
+import static com.android.launcher3.Flags.enableWorkspaceInflation;
 import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
@@ -66,6 +69,8 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
+import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.SHOW;
 import static com.android.launcher3.logging.StatsLogManager.EventEnum;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -74,6 +79,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RECONFIGURED;
@@ -85,7 +91,6 @@
 import static com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.WARM;
 import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED;
 import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP;
-import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
 import static com.android.launcher3.popup.SystemShortcut.INSTALL;
 import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
@@ -97,7 +102,6 @@
 import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
 
 import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
@@ -115,6 +119,8 @@
 import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -130,6 +136,7 @@
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
@@ -139,6 +146,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.OvershootInterpolator;
@@ -152,6 +161,7 @@
 import androidx.annotation.StringRes;
 import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
+import androidx.window.embedding.RuleController;
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -191,8 +201,9 @@
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.StringCache;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -203,7 +214,6 @@
 import com.android.launcher3.popup.ArrowPopup;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.statemanager.StatefulActivity;
@@ -212,7 +222,6 @@
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.AllAppsSwipeController;
 import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.ActivityResultInfo;
 import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.BackPressHandler;
@@ -220,10 +229,12 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInflater;
 import com.android.launcher3.util.KeyboardShortcutsDelegate;
 import com.android.launcher3.util.LockedUserState;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.ScreenOnTracker;
 import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
@@ -233,7 +244,6 @@
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.util.ViewOnDrawExecutor;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.ComposeInitializer;
 import com.android.launcher3.views.FloatingIconView;
@@ -251,16 +261,16 @@
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
+import com.android.launcher3.widget.util.WidgetSizes;
 import com.android.systemui.plugins.LauncherOverlayPlugin;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.shared.LauncherOverlayManager;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
-import com.android.wm.shell.Flags;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
+import com.android.window.flags.Flags;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -312,10 +322,6 @@
     private static final FloatProperty<Hotseat> HOTSEAT_WIDGET_SCALE =
             HOTSEAT_SCALE_PROPERTY_FACTORY.get(SCALE_INDEX_WIDGET_TRANSITION);
 
-    private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
-    private static final boolean DESKTOP_MODE_SUPPORTED =
-            "1".equals(Utilities.getSystemProperty("persist.wm.debug.desktop_mode_2", "0"));
-
     private final ModelCallbacks mModelCallbacks = createModelCallbacks();
 
     private final KeyboardShortcutsDelegate mKeyboardShortcutsDelegate =
@@ -328,6 +334,7 @@
 
     private WidgetManagerHelper mAppWidgetManager;
     private LauncherWidgetHolder mAppWidgetHolder;
+    private ItemInflater<Launcher> mItemInflater;
 
     private final int[] mTmpAddItemCellCoordinates = new int[2];
 
@@ -510,11 +517,14 @@
         mStateManager = new StateManager<>(this, NORMAL);
 
         setupViews();
+        updateDisallowBack();
 
         mAppWidgetManager = new WidgetManagerHelper(this);
         mAppWidgetHolder = createAppWidgetHolder();
         mAppWidgetHolder.startListening();
         mAppWidgetHolder.addProviderChangeListener(() -> refreshAndBindWidgetsForPackageUser(null));
+        mItemInflater = new ItemInflater<>(this, mAppWidgetHolder, getItemOnClickListener(),
+                mFocusHandler, new CellLayout(mWorkspace.getContext(), mWorkspace));
 
         mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
 
@@ -566,17 +576,20 @@
                 Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
 
         mOverlayManager = getDefaultOverlay();
-        PluginManagerWrapper.INSTANCE.get(this).addPluginListener(this,
-                LauncherOverlayPlugin.class, false /* allowedMultiple */);
+        PluginManagerWrapper.INSTANCE.get(this)
+                .addPluginListener(this, LauncherOverlayPlugin.class);
 
         mRotationHelper.initialize();
         TraceHelper.INSTANCE.endSection();
 
-        if (Utilities.ATLEAST_R) {
-            getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
-        }
+        getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
         setTitle(R.string.home_screen);
         mStartupLatencyLogger.logEnd(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
+
+        if (com.android.launcher3.Flags.enableTwoPaneLauncherSettings()) {
+            RuleController.getInstance(this).setRules(
+                    RuleController.parseRules(this, R.xml.split_configuration));
+        }
     }
 
     protected ModelCallbacks createModelCallbacks() {
@@ -650,6 +663,11 @@
         // #5 state handler
         return new OnBackAnimationCallback() {
             @Override
+            public void onBackStarted(BackEvent backEvent) {
+                Launcher.this.onBackStarted();
+            }
+
+            @Override
             public void onBackInvoked() {
                 onStateBack();
             }
@@ -662,7 +680,7 @@
 
             @Override
             public void onBackCancelled() {
-                mStateManager.getState().onBackCancelled(Launcher.this);
+                Launcher.this.onBackCancelled();
             }
         };
     }
@@ -787,13 +805,19 @@
     @Override
     public void invalidateParent(ItemInfo info) {
         if (info.container >= 0) {
-            View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
-            if (folderIcon instanceof FolderIcon && folderIcon.getTag() instanceof FolderInfo) {
+            View collectionIcon = getWorkspace().getHomescreenIconByItemId(info.container);
+            if (collectionIcon instanceof FolderIcon folderIcon
+                    && collectionIcon.getTag() instanceof FolderInfo) {
                 if (new FolderGridOrganizer(getDeviceProfile())
                         .setFolderInfo((FolderInfo) folderIcon.getTag())
                         .isItemInPreview(info.rank)) {
                     folderIcon.invalidate();
                 }
+            } else if (collectionIcon instanceof AppPairIcon appPairIcon
+                    && collectionIcon.getTag() instanceof AppPairInfo appPairInfo) {
+                if (appPairInfo.getContents().contains(info)) {
+                    appPairIcon.getIconDrawableArea().redraw();
+                }
             }
         }
     }
@@ -819,7 +843,7 @@
                 announceForAccessibility(R.string.item_added_to_workspace);
                 break;
             case REQUEST_CREATE_APPWIDGET:
-                completeAddAppWidget(appWidgetId, info, null, null);
+                completeAddAppWidget(appWidgetId, info, null, null, false, true, null);
                 break;
             case REQUEST_RECONFIGURE_APPWIDGET:
                 getStatsLogManager().logger().withItemInfo(info).log(LAUNCHER_WIDGET_RECONFIGURED);
@@ -1006,11 +1030,18 @@
         AppWidgetHostView boundWidget = null;
         if (resultCode == RESULT_OK) {
             animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
-            final AppWidgetHostView layout = mAppWidgetHolder.createView(this, appWidgetId,
-                    requestArgs.getWidgetHandler().getProviderInfo(this));
+
+            // Now that we are exiting the config activity with RESULT_OK.
+            // If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled, we can retrieve the
+            // PendingAppWidgetHostView from LauncherWidgetHolder (it was added to
+            // LauncherWidgetHolder when starting the config activity).
+            final AppWidgetHostView layout = enableAddAppWidgetViaConfigActivityV2()
+                    ? getWorkspace().getWidgetForAppWidgetId(appWidgetId)
+                    : mAppWidgetHolder.createView(appWidgetId,
+                            requestArgs.getWidgetHandler().getProviderInfo(this));
             boundWidget = layout;
             onCompleteRunnable = () -> {
-                completeAddAppWidget(appWidgetId, requestArgs, layout, null);
+                completeAddAppWidget(appWidgetId, requestArgs, layout, null, false, true, null);
                 if (!isInState(EDIT_MODE)) {
                     mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
                 }
@@ -1075,6 +1106,25 @@
 
         DiscoveryBounce.showForHomeIfNeeded(this);
         mAppWidgetHolder.setActivityResumed(true);
+
+        // Listen for IME changes to keep state up to date.
+        getRootView().setWindowInsetsAnimationCallback(
+                new WindowInsetsAnimation.Callback(DISPATCH_MODE_CONTINUE_ON_SUBTREE) {
+                    @Override
+                    public WindowInsets onProgress(WindowInsets windowInsets,
+                            List<WindowInsetsAnimation> windowInsetsAnimations) {
+                        return windowInsets;
+                    }
+
+                    @Override
+                    public void onEnd(WindowInsetsAnimation animation) {
+                        WindowInsets insets = getRootView().getRootWindowInsets();
+                        boolean isImeVisible =
+                                insets != null && insets.isVisible(WindowInsets.Type.ime());
+                        getStatsLogManager().keyboardStateManager().setKeyboardState(
+                                isImeVisible ? SHOW : HIDE);
+                    }
+                });
     }
 
     private void logStopAndResume(boolean isResume) {
@@ -1345,35 +1395,6 @@
     }
 
     /**
-     * Creates a view representing a shortcut.
-     *
-     * @param info The data structure describing the shortcut.
-     */
-    View createShortcut(WorkspaceItemInfo info) {
-        // This can be called before PagedView#pageScrollsInitialized returns true, so use the
-        // first page, which we always assume to be present.
-        return createShortcut((ViewGroup) mWorkspace.getChildAt(0), info);
-    }
-
-    /**
-     * Creates a view representing a shortcut inflated from the specified resource.
-     *
-     * @param parent The group the shortcut belongs to. This is not necessarily the group where
-     *               the shortcut should be added.
-     * @param info   The data structure describing the shortcut.
-     * @return A View inflated from layoutResId.
-     */
-    public View createShortcut(@Nullable ViewGroup parent, WorkspaceItemInfo info) {
-        BubbleTextView favorite =
-                (BubbleTextView) LayoutInflater.from(parent != null ? parent.getContext() : this)
-                        .inflate(R.layout.app_icon, parent, false);
-        favorite.applyFromWorkspaceItem(info);
-        favorite.setOnClickListener(getItemOnClickListener());
-        favorite.setOnFocusChangeListener(mFocusHandler);
-        return favorite;
-    }
-
-    /**
      * Add a shortcut to the workspace or to a Folder.
      *
      * @param data The intent describing the shortcut.
@@ -1396,7 +1417,7 @@
 
         if (container < 0) {
             // Adding a shortcut to the Workspace.
-            final View view = createShortcut(info);
+            final View view = mItemInflater.inflateItem(info, getModelWriter());
             boolean foundCellSpan = false;
             // First we check if we already know the exact location where we want to add this item.
             if (cellX >= 0 && cellY >= 0) {
@@ -1450,16 +1471,18 @@
      */
     @Thunk
     void completeAddAppWidget(int appWidgetId, ItemInfo itemInfo,
-            AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
+            @Nullable AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo,
+            boolean showPendingWidget, boolean updateWidgetSize,
+            @Nullable Bitmap widgetPreviewBitmap) {
 
         if (appWidgetInfo == null) {
             appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId,
                     itemInfo.getTargetComponent());
         }
 
-        if (hostView == null) {
+        if (hostView == null && !showPendingWidget) {
             // Perform actual inflation because we're live
-            hostView = mAppWidgetHolder.createView(this, appWidgetId, appWidgetInfo);
+            hostView = mAppWidgetHolder.createView(appWidgetId, appWidgetInfo);
         }
 
         LauncherAppWidgetInfo launcherInfo;
@@ -1471,47 +1494,83 @@
         launcherInfo.minSpanX = itemInfo.minSpanX;
         launcherInfo.minSpanY = itemInfo.minSpanY;
         launcherInfo.user = appWidgetInfo.getProfile();
+        CellPos presenterPos = getCellPosMapper().mapModelToPresenter(itemInfo);
+        if (showPendingWidget) {
+            launcherInfo.restoreStatus = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+            PendingAppWidgetHostView pendingAppWidgetHostView = new PendingAppWidgetHostView(
+                    this, mAppWidgetHolder, launcherInfo, appWidgetInfo, widgetPreviewBitmap);
+            hostView = pendingAppWidgetHostView;
+        } else if (hostView instanceof PendingAppWidgetHostView) {
+            ((PendingAppWidgetHostView) hostView).setPreviewBitmapAndUpdateBackground(null);
+            // User has selected a widget config and exited the config activity, we can trigger
+            // re-inflation of PendingAppWidgetHostView to replace it with
+            // LauncherAppWidgetHostView in workspace.
+            completeRestoreAppWidget(appWidgetId, LauncherAppWidgetInfo.RESTORE_COMPLETED);
+
+            // Show resize frame on the newly inflated LauncherAppWidgetHostView.
+            LauncherAppWidgetHostView reInflatedHostView =
+                    getWorkspace().getWidgetForAppWidgetId(appWidgetId);
+            showWidgetResizeFrame(
+                    reInflatedHostView,
+                    (LauncherAppWidgetInfo) reInflatedHostView.getTag(),
+                    presenterPos);
+            // We always update widget size after re-inflating PendingAppWidgetHostView
+            WidgetSizes.updateWidgetSizeRanges(
+                    reInflatedHostView, this, itemInfo.spanX, itemInfo.spanY);
+            return;
+        }
+        if (updateWidgetSize) {
+            WidgetSizes.updateWidgetSizeRanges(hostView, this, itemInfo.spanX, itemInfo.spanY);
+        }
         if (itemInfo instanceof PendingAddWidgetInfo) {
             launcherInfo.sourceContainer = ((PendingAddWidgetInfo) itemInfo).sourceContainer;
         } else if (itemInfo instanceof PendingRequestArgs) {
             launcherInfo.sourceContainer =
                     ((PendingRequestArgs) itemInfo).getWidgetSourceContainer();
         }
-        CellPos presenterPos = getCellPosMapper().mapModelToPresenter(itemInfo);
         getModelWriter().addItemToDatabase(launcherInfo,
                 itemInfo.container, presenterPos.screenId, presenterPos.cellX, presenterPos.cellY);
 
         hostView.setVisibility(View.VISIBLE);
-        prepareAppWidget(hostView, launcherInfo);
-        mWorkspace.addInScreen(hostView, launcherInfo);
+        mItemInflater.prepareAppWidget(hostView, launcherInfo);
+        if (!enableAddAppWidgetViaConfigActivityV2() || hostView.getParent() == null) {
+            mWorkspace.addInScreen(hostView, launcherInfo);
+        }
         announceForAccessibility(R.string.item_added_to_workspace);
 
         // Show the widget resize frame.
         if (hostView instanceof LauncherAppWidgetHostView) {
             final LauncherAppWidgetHostView launcherHostView = (LauncherAppWidgetHostView) hostView;
-            CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId);
-            if (mStateManager.getState() == NORMAL) {
-                AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
-            } else {
-                mStateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
-                    @Override
-                    public void onStateTransitionComplete(LauncherState finalState) {
-                        if ((mPrevLauncherState == SPRING_LOADED || mPrevLauncherState == EDIT_MODE)
-                                && finalState == NORMAL) {
-                            AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
-                            mStateManager.removeStateListener(this);
-                        }
-                    }
-                });
-            }
+            showWidgetResizeFrame(launcherHostView, launcherInfo, presenterPos);
         }
     }
 
-    private void prepareAppWidget(AppWidgetHostView hostView, LauncherAppWidgetInfo item) {
-        hostView.setTag(item);
-        item.onBindAppWidget(this, hostView);
-        hostView.setFocusable(true);
-        hostView.setOnFocusChangeListener(mFocusHandler);
+    /** Show widget resize frame. */
+    private void showWidgetResizeFrame(
+            LauncherAppWidgetHostView launcherHostView,
+            LauncherAppWidgetInfo launcherInfo,
+            CellPos presenterPos) {
+        CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId);
+        // We should wait until launcher is not animating to show resize frame so that
+        // {@link View#hasIdentityMatrix()} returns true (no scale effect) from CellLayout and
+        // Workspace (they are widget's parent view). Otherwise widget's
+        // {@link View#getLocationInWindow(int[])} will set skewed location, causing resize
+        // frame not showing at skewed location in
+        // {@link AppWidgetResizeFrame#snapToWidget(boolean)}.
+        if (mStateManager.getState() == NORMAL && !mStateManager.isInTransition()) {
+            AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
+        } else {
+            mStateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
+                @Override
+                public void onStateTransitionComplete(LauncherState finalState) {
+                    if ((mPrevLauncherState == SPRING_LOADED || mPrevLauncherState == EDIT_MODE)
+                            && finalState == NORMAL) {
+                        AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
+                        mStateManager.removeStateListener(this);
+                    }
+                }
+            });
+        }
     }
 
     private final ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
@@ -1587,27 +1646,33 @@
             }
 
             if (FeatureFlags.enableSplitContextually()) {
-                handleSplitAnimationGoingToHome();
+                handleSplitAnimationGoingToHome(LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
             }
             mOverlayManager.hideOverlay(isStarted() && !isForceInvisible());
             handleGestureContract(intent);
         } else if (Intent.ACTION_ALL_APPS.equals(intent.getAction())) {
             showAllAppsFromIntent(alreadyOnHome);
         } else if (INTENT_ACTION_ALL_APPS_TOGGLE.equals(intent.getAction())) {
-            toggleAllAppsFromIntent(alreadyOnHome);
+            toggleAllAppsSearch(alreadyOnHome);
         } else if (Intent.ACTION_SHOW_WORK_APPS.equals(intent.getAction())) {
-            showAllAppsWorkTabFromIntent(alreadyOnHome);
+            showAllAppsWithSelectedTabFromIntent(alreadyOnHome,
+                    ActivityAllAppsContainerView.AdapterHolder.WORK);
         }
 
         TraceHelper.INSTANCE.endSection();
     }
 
     /** Handle animating away split placeholder view when user taps on home button */
-    protected void handleSplitAnimationGoingToHome() {
+    protected void handleSplitAnimationGoingToHome(EventEnum splitDismissReason) {
         // Overridden
     }
 
-    protected void toggleAllAppsFromIntent(boolean alreadyOnHome) {
+    /** Toggles Launcher All Apps with keyboard ready for search. */
+    public void toggleAllAppsSearch() {
+        toggleAllAppsSearch(/* alreadyOnHome= */ true);
+    }
+
+    protected void toggleAllAppsSearch(boolean alreadyOnHome) {
         if (getStateManager().isInStableState(ALL_APPS)) {
             getStateManager().goToState(NORMAL, alreadyOnHome);
         } else {
@@ -1628,13 +1693,19 @@
     }
 
     protected void showAllAppsFromIntent(boolean alreadyOnHome) {
-        AbstractFloatingView.closeAllOpenViews(this);
-        getStateManager().goToState(ALL_APPS, alreadyOnHome);
+        showAllAppsWithSelectedTabFromIntent(alreadyOnHome,
+                ActivityAllAppsContainerView.AdapterHolder.MAIN);
     }
 
-    private void showAllAppsWorkTabFromIntent(boolean alreadyOnHome) {
-        showAllAppsFromIntent(alreadyOnHome);
-        mAppsView.switchToTab(ActivityAllAppsContainerView.AdapterHolder.WORK);
+    private void showAllAppsWithSelectedTabFromIntent(boolean alreadyOnHome, int tab) {
+        AbstractFloatingView.closeAllOpenViews(this);
+        getStateManager().goToState(ALL_APPS, alreadyOnHome);
+        if (mAppsView.isSearching()) {
+            mAppsView.reset(alreadyOnHome);
+        }
+        if (mAppsView.getCurrentPage() != tab) {
+            mAppsView.switchToTab(tab);
+        }
     }
 
     /**
@@ -1710,11 +1781,7 @@
         mModel.removeCallbacks(this);
         mRotationHelper.destroy();
 
-        try {
-            mAppWidgetHolder.stopListening();
-        } catch (NullPointerException ex) {
-            Log.w(TAG, "problem while stopping AppWidgetHost during Launcher destruction", ex);
-        }
+        mAppWidgetHolder.stopListening();
         mAppWidgetHolder.destroy();
 
         TextKeyListener.getInstance().release();
@@ -1771,19 +1838,41 @@
         addAppWidgetImpl(appWidgetId, info, boundWidget, addFlowHandler, 0);
     }
 
+    /**
+     * If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled, we always add widget
+     * host view to workspace, otherwise we only add widget to host view if config activity is
+     * not started.
+     */
     void addAppWidgetImpl(int appWidgetId, ItemInfo info,
             AppWidgetHostView boundWidget, WidgetAddFlowHandler addFlowHandler, int delay) {
-        if (!addFlowHandler.startConfigActivity(this, appWidgetId, info,
-                REQUEST_CREATE_APPWIDGET)) {
-            // If the configuration flow was not started, add the widget
+        final boolean isActivityStarted = addFlowHandler.startConfigActivity(
+                this, appWidgetId, info, REQUEST_CREATE_APPWIDGET);
 
-            // Exit spring loaded mode if necessary after adding the widget
-            Runnable onComplete = MULTI_SELECT_EDIT_MODE.get() ? null
-                    : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
-            completeAddAppWidget(appWidgetId, info, boundWidget,
-                    addFlowHandler.getProviderInfo(this));
-            mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
+        if (!enableAddAppWidgetViaConfigActivityV2() && isActivityStarted) {
+            return;
         }
+
+        // If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled and config activity is
+        // started, we should remove the dropped AppWidgetHostView from drag layer and extract the
+        // Bitmap that shows the preview. Then pass the Bitmap to completeAddAppWidget() to create
+        // a PendingWidgetHostView.
+        Bitmap widgetPreviewBitmap = null;
+        if (isActivityStarted) {
+            DragView dropView = getDragLayer().clearAnimatedView();
+            if (dropView != null && dropView.containsAppWidgetHostView()) {
+                // Extracting Bitmap from dropView instead of its content view produces the correct
+                // bitmap.
+                widgetPreviewBitmap = getBitmapFromView(dropView);
+            }
+        }
+
+        // Exit spring loaded mode if necessary after adding the widget
+        Runnable onComplete = MULTI_SELECT_EDIT_MODE.get() ? null
+                : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+        completeAddAppWidget(appWidgetId, info, boundWidget,
+                addFlowHandler.getProviderInfo(this), addFlowHandler.needsConfigure(),
+                false, widgetPreviewBitmap);
+        mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
     }
 
     public void addPendingItem(PendingAddItemInfo info, int container, int screenId,
@@ -1938,24 +2027,26 @@
     public boolean removeItem(View v, final ItemInfo itemInfo, boolean deleteFromDb,
             @Nullable final String reason) {
         if (itemInfo instanceof WorkspaceItemInfo) {
-            // Remove the shortcut from the folder before removing it from launcher
-            View folderIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
-            if (folderIcon instanceof FolderIcon) {
-                ((FolderInfo) folderIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+            View collectionIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
+            if (collectionIcon instanceof FolderIcon) {
+                // Remove the shortcut from the folder before removing it from launcher
+                ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+            } else if (collectionIcon instanceof AppPairIcon appPairIcon) {
+                removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb,
+                        "removing app pair because one of its member apps was removed");
             } else {
                 mWorkspace.removeWorkspaceItem(v);
             }
             if (deleteFromDb) {
                 getModelWriter().deleteItemFromDatabase(itemInfo, reason);
             }
-        } else if (itemInfo instanceof FolderInfo) {
-            final FolderInfo folderInfo = (FolderInfo) itemInfo;
+        } else if (itemInfo instanceof CollectionInfo ci) {
             if (v instanceof FolderIcon) {
                 ((FolderIcon) v).removeListeners();
             }
             mWorkspace.removeWorkspaceItem(v);
             if (deleteFromDb) {
-                getModelWriter().deleteFolderAndContentsFromDatabase(folderInfo);
+                getModelWriter().deleteCollectionAndContentsFromDatabase(ci);
             }
         } else if (itemInfo instanceof LauncherAppWidgetInfo) {
             final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
@@ -1998,8 +2089,16 @@
         getOnBackAnimationCallback().onBackInvoked();
     }
 
+    protected void onBackStarted() {
+        mStateManager.getState().onBackStarted(this);
+    }
+
     protected void onStateBack() {
-        mStateManager.getState().onBackPressed(this);
+        mStateManager.getState().onBackInvoked(this);
+    }
+
+    protected void onBackCancelled() {
+        mStateManager.getState().onBackCancelled(this);
     }
 
     protected void onScreenOnChanged(boolean isOn) {
@@ -2135,82 +2234,36 @@
      */
     @Override
     public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
-        bindItems(items, forceAnimateIcons, /* focusFirstItemForAccessibility= */ false);
+        bindInflatedItems(items.stream().map(i -> Pair.create(
+                i, getItemInflater().inflateItem(i, getModelWriter()))).toList(),
+                forceAnimateIcons ? new AnimatorSet() : null);
     }
 
+    @Override
+    public void bindInflatedItems(List<Pair<ItemInfo, View>> items) {
+        bindInflatedItems(items, null);
+    }
 
     /**
-     * Bind the items start-end from the list.
+     * Bind all the items in the map, ignoring any null views
      *
-     * Implementation of the method from LauncherModel.Callbacks.
-     *
-     * @param focusFirstItemForAccessibility true iff the first item to be added to the workspace
-     *                                       should be focused for accessibility.
+     * @param boundAnim if non-null, uses it to create and play the bounce animation for added views
      */
-    public void bindItems(
-            final List<ItemInfo> items,
-            final boolean forceAnimateIcons,
-            final boolean focusFirstItemForAccessibility) {
+    public void bindInflatedItems(
+            List<Pair<ItemInfo, View>> shortcuts, @Nullable AnimatorSet boundAnim) {
         // Get the list of added items and intersect them with the set of items here
-        final Collection<Animator> bounceAnims = new ArrayList<>();
-        boolean canAnimatePageChange = canAnimatePageChange();
         Workspace<?> workspace = mWorkspace;
         int newItemsScreenId = -1;
-        int end = items.size();
-        View newView = null;
-        for (int i = 0; i < end; i++) {
-            final ItemInfo item = items.get(i);
+        int index = 0;
+        for (Pair<ItemInfo, View> e : shortcuts) {
+            final ItemInfo item = e.first;
 
-            // Short circuit if we are loading dock items for a configuration which has no dock
-            if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
-                    mHotseat == null) {
-                continue;
-            }
-
-            final View view;
-            switch (item.itemType) {
-                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
-                    WorkspaceItemInfo info = (WorkspaceItemInfo) item;
-                    view = createShortcut(info);
-                    break;
-                }
-                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
-                    view = FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, this,
-                            (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
-                            (FolderInfo) item);
-                    break;
-                }
-                case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR: {
-                    view = AppPairIcon.inflateIcon(R.layout.app_pair_icon, this,
-                            (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()),
-                            (FolderInfo) item);
-                    break;
-                }
-                case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET: {
-                    view = inflateAppWidget((LauncherAppWidgetInfo) item);
-                    if (view == null) {
-                        continue;
-                    }
-                    break;
-                }
-                default:
-                    throw new RuntimeException("Invalid Item Type");
-            }
-
-            /*
-             * Remove colliding items.
-             */
+            // Remove colliding items.
             CellPos presenterPos = getCellPosMapper().mapModelToPresenter(item);
             if (item.container == CONTAINER_DESKTOP) {
                 CellLayout cl = mWorkspace.getScreenWithId(presenterPos.screenId);
                 if (cl != null && cl.isOccupied(presenterPos.cellX, presenterPos.cellY)) {
-                    View v = cl.getChildAt(presenterPos.cellX, presenterPos.cellY);
-                    if (v == null) {
-                        Log.e(TAG, "bindItems failed when removing colliding item=" + item);
-                    }
-                    Object tag = v.getTag();
+                    Object tag = cl.getChildAt(presenterPos.cellX, presenterPos.cellY).getTag();
                     String desc = "Collision while binding workspace item: " + item
                             + ". Collides with " + tag;
                     if (FeatureFlags.IS_STUDIO_BUILD) {
@@ -2221,58 +2274,42 @@
                     }
                 }
             }
+
+            View view = e.second;
+            if (view == null) {
+                continue;
+            }
+            if (enableWorkspaceInflation() && view instanceof LauncherAppWidgetHostView lv) {
+                view = getAppWidgetHolder().attachViewToHostAndGetAttachedView(lv);
+            }
             workspace.addInScreenFromBind(view, item);
-            if (forceAnimateIcons) {
+            if (boundAnim != null) {
                 // Animate all the applications up now
                 view.setAlpha(0f);
                 view.setScaleX(0f);
                 view.setScaleY(0f);
-                bounceAnims.add(createNewAppBounceAnimation(view, i));
+                boundAnim.play(createNewAppBounceAnimation(view, index++));
                 newItemsScreenId = presenterPos.screenId;
             }
-
-            if (newView == null) {
-                newView = view;
-            }
         }
 
-        View viewToFocus = newView;
-        // Animate to the correct pager
-        if (forceAnimateIcons && newItemsScreenId > -1) {
-            AnimatorSet anim = new AnimatorSet();
-            anim.playTogether(bounceAnims);
-            if (focusFirstItemForAccessibility && viewToFocus != null) {
-                anim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
-                    }
-                });
-            }
-
+        // Animate to the correct page
+        if (boundAnim != null && newItemsScreenId > -1) {
             int currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
             final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
-            final Runnable startBounceAnimRunnable = anim::start;
+            final Runnable startBounceAnimRunnable = boundAnim::start;
 
-            if (canAnimatePageChange && newItemsScreenId != currentScreenId) {
+            if (canAnimatePageChange() && newItemsScreenId != currentScreenId) {
                 // We post the animation slightly delayed to prevent slowdowns
                 // when we are loading right after we return to launcher.
-                mWorkspace.postDelayed(new Runnable() {
-                    public void run() {
-                        if (mWorkspace != null) {
-                            closeOpenViews(false);
-
-                            mWorkspace.snapToPage(newScreenIndex);
-                            mWorkspace.postDelayed(startBounceAnimRunnable,
-                                    NEW_APPS_ANIMATION_DELAY);
-                        }
-                    }
+                mWorkspace.postDelayed(() -> {
+                    closeOpenViews(false);
+                    mWorkspace.snapToPage(newScreenIndex);
+                    mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
                 }, NEW_APPS_PAGE_MOVE_DELAY);
             } else {
                 mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
             }
-        } else if (focusFirstItemForAccessibility && viewToFocus != null) {
-            viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         }
         workspace.requestLayout();
     }
@@ -2281,166 +2318,13 @@
      * Add the views for a widget to the workspace.
      */
     public void bindAppWidget(LauncherAppWidgetInfo item) {
-        View view = inflateAppWidget(item);
+        View view = mItemInflater.inflateItem(item, getModelWriter());
         if (view != null) {
             mWorkspace.addInScreen(view, item);
             mWorkspace.requestLayout();
         }
     }
 
-    private View inflateAppWidget(LauncherAppWidgetInfo item) {
-        if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
-            item.providerName = QsbContainerView.getSearchComponentName(this);
-            if (item.providerName == null) {
-                getModelWriter().deleteItemFromDatabase(item,
-                        "search widget removed because search component cannot be found");
-                return null;
-            }
-        }
-        final AppWidgetHostView view;
-        if (mIsSafeModeEnabled) {
-            view = new PendingAppWidgetHostView(this, item, mIconCache, true);
-            prepareAppWidget(view, item);
-            return view;
-        }
-
-        TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId);
-
-        try {
-            final LauncherAppWidgetProviderInfo appWidgetInfo;
-            String removalReason = "";
-
-            if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
-                // If the provider is not ready, bind as a pending widget.
-                appWidgetInfo = null;
-                removalReason = "the provider isn't ready.";
-            } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
-                // The widget id is not valid. Try to find the widget based on the provider info.
-                appWidgetInfo = mAppWidgetManager.findProvider(item.providerName, item.user);
-                if (appWidgetInfo == null) {
-                    if (WidgetsModel.GO_DISABLE_WIDGETS) {
-                        removalReason = "widgets are disabled on go device.";
-                    } else {
-                        removalReason =
-                                "WidgetManagerHelper cannot find a provider from provider info.";
-                    }
-                }
-            } else {
-                appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(item.appWidgetId,
-                        item.getTargetComponent());
-                if (appWidgetInfo == null) {
-                    if (item.appWidgetId <= CUSTOM_WIDGET_ID) {
-                        removalReason =
-                                "CustomWidgetManager cannot find provider from that widget id.";
-                    } else {
-                        removalReason = "AppWidgetManager cannot find provider for that widget id."
-                                + " It could be because AppWidgetService is not available, or the"
-                                + " appWidgetId has not been bound to a the provider yet, or you"
-                                + " don't have access to that appWidgetId.";
-                    }
-                }
-            }
-
-            // If the provider is ready, but the width is not yet restored, try to restore it.
-            if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)
-                    && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) {
-                if (appWidgetInfo == null) {
-                    getModelWriter().deleteItemFromDatabase(item,
-                            "Removing restored widget: id=" + item.appWidgetId
-                            + " belongs to component " + item.providerName + " user " + item.user
-                            + ", as the provider is null and " + removalReason);
-                    return null;
-                }
-
-                // If we do not have a valid id, try to bind an id.
-                if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
-                    if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
-                        // Id has not been allocated yet. Allocate a new id.
-                        item.appWidgetId = mAppWidgetHolder.allocateAppWidgetId();
-                        item.restoreStatus |= LauncherAppWidgetInfo.FLAG_ID_ALLOCATED;
-
-                        // Also try to bind the widget. If the bind fails, the user will be shown
-                        // a click to setup UI, which will ask for the bind permission.
-                        PendingAddWidgetInfo pendingInfo =
-                                new PendingAddWidgetInfo(appWidgetInfo, item.sourceContainer);
-                        pendingInfo.spanX = item.spanX;
-                        pendingInfo.spanY = item.spanY;
-                        pendingInfo.minSpanX = item.minSpanX;
-                        pendingInfo.minSpanY = item.minSpanY;
-                        Bundle options = pendingInfo.getDefaultSizeOptions(this);
-
-                        boolean isDirectConfig =
-                                item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG);
-                        if (isDirectConfig && item.bindOptions != null) {
-                            Bundle newOptions = item.bindOptions.getExtras();
-                            if (options != null) {
-                                newOptions.putAll(options);
-                            }
-                            options = newOptions;
-                        }
-                        boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
-                                item.appWidgetId, appWidgetInfo, options);
-
-                        // We tried to bind once. If we were not able to bind, we would need to
-                        // go through the permission dialog, which means we cannot skip the config
-                        // activity.
-                        item.bindOptions = null;
-                        item.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG;
-
-                        // Bind succeeded
-                        if (success) {
-                            // If the widget has a configure activity, it is still needs to set it
-                            // up, otherwise the widget is ready to go.
-                            item.restoreStatus = (appWidgetInfo.configure == null) || isDirectConfig
-                                    ? LauncherAppWidgetInfo.RESTORE_COMPLETED
-                                    : LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-                        }
-
-                        getModelWriter().updateItemInDatabase(item);
-                    }
-                } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
-                        && (appWidgetInfo.configure == null)) {
-                    // The widget was marked as UI not ready, but there is no configure activity to
-                    // update the UI.
-                    item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
-                    getModelWriter().updateItemInDatabase(item);
-                }
-                else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY)
-                        && appWidgetInfo.configure != null) {
-                    if (mAppWidgetManager.isAppWidgetRestored(item.appWidgetId)) {
-                        item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED;
-                        getModelWriter().updateItemInDatabase(item);
-                    }
-                }
-            }
-
-            if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
-                // Verify that we own the widget
-                if (appWidgetInfo == null) {
-                    FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
-                    getModelWriter().deleteWidgetInfo(item, getAppWidgetHolder(), removalReason);
-                    return null;
-                }
-
-                item.minSpanX = appWidgetInfo.minSpanX;
-                item.minSpanY = appWidgetInfo.minSpanY;
-                view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
-            } else if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
-                    && appWidgetInfo != null) {
-                mAppWidgetHolder.addPendingView(item.appWidgetId,
-                        new PendingAppWidgetHostView(this, item, mIconCache, false));
-                view = mAppWidgetHolder.createView(this, item.appWidgetId, appWidgetInfo);
-            } else {
-                view = new PendingAppWidgetHostView(this, item, mIconCache, false);
-            }
-            prepareAppWidget(view, item);
-        } finally {
-            TraceHelper.INSTANCE.endSection();
-        }
-
-        return view;
-    }
-
     /**
      * Restores a pending widget.
      *
@@ -2448,7 +2332,7 @@
      */
     private LauncherAppWidgetInfo completeRestoreAppWidget(int appWidgetId, int finalRestoreFlag) {
         LauncherAppWidgetHostView view = mWorkspace.getWidgetForAppWidgetId(appWidgetId);
-        if ((view == null) || !(view instanceof PendingAppWidgetHostView)) {
+        if (!(view instanceof PendingAppWidgetHostView)) {
             Log.e(TAG, "Widget update called, when the widget no longer exists.");
             return null;
         }
@@ -2459,20 +2343,15 @@
             info.pendingItemInfo = null;
         }
 
-        if (((PendingAppWidgetHostView) view).isReinflateIfNeeded()) {
-            view.reInflate();
+        PendingAppWidgetHostView pv = (PendingAppWidgetHostView) view;
+        if (pv.isReinflateIfNeeded()) {
+            pv.reInflate();
         }
 
         getModelWriter().updateItemInDatabase(info);
         return info;
     }
 
-    public void clearPendingExecutor(ViewOnDrawExecutor executor) {
-        if (mModelCallbacks.getPendingExecutor() == executor) {
-            mModelCallbacks.setPendingExecutor(null);
-        }
-    }
-
     /**
      * Call back when ModelCallbacks finish binding the Launcher data.
      */
@@ -2501,9 +2380,9 @@
 
     @Override
     public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
-            int workspaceItemCount, boolean isBindSync) {
-        mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, workspaceItemCount,
-                isBindSync);
+            RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
+        mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
+                workspaceItemCount, isBindSync);
     }
 
     /**
@@ -2528,7 +2407,8 @@
      * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
      * animation.
      *
-     * @param preferredItemId The id of the preferred item to match to if it exists.
+     * @param preferredItemId The id of the preferred item to match to if it exists,
+     *                        or ItemInfo#NO_MATCHING_ID if you want to not match by item id
      * @param packageName The package name of the app to match.
      * @param user The user of the app to match.
      * @param supportsAllAppsState If true and we are in All Apps state, looks for view in All Apps.
@@ -2607,6 +2487,18 @@
         return null;
     }
 
+    /** Convert a {@link View} to {@link Bitmap}. */
+    private static Bitmap getBitmapFromView(@Nullable View view) {
+        if (view == null) {
+            return null;
+        }
+        Bitmap returnedBitmap =
+                Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(returnedBitmap);
+        view.draw(canvas);
+        return returnedBitmap;
+    }
+
     /**
      * Returns the first view matching the operator in the given ViewGroups, or null if none.
      * Forward iteration matters.
@@ -2616,7 +2508,13 @@
         final int itemCount = container.getChildCount();
         for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
             View item = container.getChildAt(itemIdx);
-            if (op.test((ItemInfo) item.getTag())) {
+            if (item instanceof ViewGroup viewGroup) {
+                View view = mapOverViewGroup(viewGroup, op);
+                if (view != null) {
+                    return view;
+                }
+            }
+            if (item.getTag() instanceof ItemInfo itemInfo && op.test(itemInfo)) {
                 return item;
             }
         }
@@ -2793,6 +2691,7 @@
 
         mModel.dumpState(prefix, fd, writer, args);
         mOverlayManager.dump(prefix, writer);
+        ACTIVITY_TRACKER.dump(prefix, writer);
     }
 
     /**
@@ -2879,14 +2778,13 @@
     }
 
     private void updateDisallowBack() {
-        // TODO(b/304778354): remove sysprop once desktop aconfig flag supports dynamic overriding
-        if (ENABLE_DESKTOP_WINDOWING || DESKTOP_MODE_SUPPORTED) {
-            // Do not disable back in launcher when prototype behavior is enabled
+        if (Flags.enableDesktopWindowingMode()) {
+            // TODO(b/330183377) disable back in launcher when when we productionize
             return;
         }
         LauncherRootView rv = getRootView();
         if (rv != null) {
-            boolean isSplitSelectionEnabled = isSplitSelectionEnabled();
+            boolean isSplitSelectionEnabled = isSplitSelectionActive();
             boolean disableBack = getStateManager().getState() == NORMAL
                     && AbstractFloatingView.getTopOpenView(this) == null
                     && !isSplitSelectionEnabled;
@@ -2895,13 +2793,13 @@
     }
 
     /** To be overridden by subclasses */
-    public boolean isSplitSelectionEnabled() {
+    public boolean isSplitSelectionActive() {
         // Overridden
         return false;
     }
 
     /** Call to dismiss the intermediary split selection state. */
-    public void dismissSplitSelection() {
+    public void dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent) {
         // Overridden; move this into ActivityContext if necessary for Taskbar
     }
 
@@ -3001,8 +2899,8 @@
      * Returns {@code true} if there are visible tasks with windowing mode set to
      * {@link android.app.WindowConfiguration#WINDOWING_MODE_FREEFORM}
      */
-    public boolean areFreeformTasksVisible() {
-        return false; // Base launcher does not track freeform tasks
+    public boolean areDesktopTasksVisible() {
+        return false; // Base launcher does not track desktop tasks
     }
 
     // Getters and Setters
@@ -3044,7 +2942,7 @@
     /**
      * Call this after onCreate to set or clear overlay.
      */
-    public void setLauncherOverlay(LauncherOverlay overlay) {
+    public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
         mWorkspace.setLauncherOverlay(overlay);
     }
 
@@ -3222,6 +3120,11 @@
         return super.getStatsLogManager().withDefaultInstanceId(mAllAppsSessionLogId);
     }
 
+    @Override
+    public ItemInflater<Launcher> getItemInflater() {
+        return mItemInflater;
+    }
+
     /**
      * Returns the current popup for testing, if any.
      */
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index c20f323..6a9d170 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -220,17 +220,28 @@
 
     /**
      * Utility method to create an {@link AnimatorListener} which executes a callback on animation
-     * cancel.
+     * cancel. Once the cancel has been dispatched, this listener will no longer be called.
      */
-    public static AnimatorListener newCancelListener(Runnable callback) {
-        return new AnimatorListenerAdapter() {
+    public static AnimatorListener newSingleUseCancelListener(Runnable callback) {
+        return newCancelListener(callback, true);
+    }
 
+    /**
+     * Utility method to create an {@link AnimatorListener} which executes a callback on animation
+     * cancel.
+     *
+     * @param isSingleUse {@code true} means the callback will be called at most once
+     */
+    public static AnimatorListener newCancelListener(Runnable callback, boolean isSingleUse) {
+        return new AnimatorListenerAdapter() {
             boolean mDispatched = false;
 
             @Override
             public void onAnimationCancel(Animator animation) {
                 if (!mDispatched) {
-                    mDispatched = true;
+                    if (isSingleUse) {
+                        mDispatched = true;
+                    }
                     callback.run();
                 }
             }
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 9a19526..d2633e0 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -34,13 +34,10 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ArchiveCompatibilityParams;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
-import android.widget.RemoteViews;
 
-import androidx.annotation.GuardedBy;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.graphics.IconShape;
@@ -48,6 +45,7 @@
 import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.icons.LauncherIconProvider;
 import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.model.ModelLauncherCallbacks;
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.InstallSessionTracker;
@@ -60,6 +58,7 @@
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 public class LauncherAppState implements SafeCloseable {
@@ -75,40 +74,43 @@
     private final LauncherIconProvider mIconProvider;
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mInvariantDeviceProfile;
+    private boolean mIsSafeModeEnabled;
+
     private final RunnableList mOnTerminateCallback = new RunnableList();
 
-    // WORKAROUND: b/269335387 remove this after widget background listener is enabled
-    /* Array of RemoteViews cached by Launcher process */
-    @GuardedBy("itself")
-    @NonNull
-    public final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
-
-    public static LauncherAppState getInstance(final Context context) {
+    public static LauncherAppState getInstance(Context context) {
         return INSTANCE.get(context);
     }
 
-    public static LauncherAppState getInstanceNoCreate() {
-        return INSTANCE.getNoCreate();
-    }
-
     public Context getContext() {
         return mContext;
     }
 
+    @SuppressWarnings("NewApi")
     public LauncherAppState(Context context) {
         this(context, LauncherFiles.APP_ICONS_DB);
         Log.v(Launcher.TAG, "LauncherAppState initiated");
         Preconditions.assertUIThread();
 
+        mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
+                () -> context.getPackageManager().isSafeMode());
         mInvariantDeviceProfile.addOnChangeListener(modelPropertiesChanged -> {
             if (modelPropertiesChanged) {
                 refreshAndReloadLauncher();
             }
         });
 
-        mContext.getSystemService(LauncherApps.class).registerCallback(mModel);
+        ModelLauncherCallbacks callbacks = mModel.newModelCallbacks();
+        LauncherApps launcherApps = mContext.getSystemService(LauncherApps.class);
+        launcherApps.registerCallback(callbacks);
         mOnTerminateCallback.add(() ->
-                mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel));
+                mContext.getSystemService(LauncherApps.class).unregisterCallback(callbacks));
+
+        if (Flags.enableSupportForArchiving()) {
+            ArchiveCompatibilityParams params = new ArchiveCompatibilityParams();
+            params.setEnableUnarchivalConfirmation(false);
+            launcherApps.setArchiveCompatibility(params);
+        }
 
         SimpleBroadcastReceiver modelChangeReceiver =
                 new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
@@ -234,6 +236,10 @@
         return mInvariantDeviceProfile;
     }
 
+    public boolean isSafeModeEnabled() {
+        return mIsSafeModeEnabled;
+    }
+
     /**
      * Shorthand for {@link #getInvariantDeviceProfile()}
      */
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index c81db63..9b0e0ec 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,15 +20,17 @@
 
 import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
 import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
+import static com.android.launcher3.icons.cache.BaseIconCache.EMPTY_CLASS_NAME;
+import static com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE;
 import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_AVAILABLE;
 import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_UNAVAILABLE;
 import static com.android.launcher3.testing.shared.TestProtocol.sDebugTracing;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller;
 import android.content.pm.ShortcutInfo;
 import android.os.UserHandle;
@@ -43,20 +45,19 @@
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.AddWorkspaceItemsTask;
 import com.android.launcher3.model.AllAppsList;
+import com.android.launcher3.model.BaseLauncherBinder;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.CacheDataUpdatedTask;
 import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.model.LauncherBinder;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.model.ModelDelegate;
+import com.android.launcher3.model.ModelLauncherCallbacks;
 import com.android.launcher3.model.ModelWriter;
-import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask;
 import com.android.launcher3.model.PackageInstallStateChangedTask;
 import com.android.launcher3.model.PackageUpdatedTask;
 import com.android.launcher3.model.ReloadStringCacheTask;
@@ -71,6 +72,7 @@
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
 
@@ -89,7 +91,7 @@
  * LauncherModel object held in a static. Also provide APIs for updating the database state
  * for the Launcher.
  */
-public class LauncherModel extends LauncherApps.Callback implements InstallSessionTracker.Callback {
+public class LauncherModel implements InstallSessionTracker.Callback {
     private static final boolean DEBUG_RECEIVER = false;
 
     static final String TAG = "Launcher.Model";
@@ -168,6 +170,10 @@
         return mModelDbController;
     }
 
+    public ModelLauncherCallbacks newModelCallbacks() {
+        return new ModelLauncherCallbacks(this::enqueueModelUpdateTask);
+    }
+
     /**
      * Adds the provided items to the workspace.
      */
@@ -186,77 +192,6 @@
                 owner);
     }
 
-    @Override
-    public void onPackageChanged(
-            @NonNull final String packageName, @NonNull final UserHandle user) {
-        int op = PackageUpdatedTask.OP_UPDATE;
-        enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
-    }
-
-    @Override
-    public void onPackageRemoved(
-            @NonNull final String packageName, @NonNull final UserHandle user) {
-        onPackagesRemoved(user, packageName);
-    }
-
-    public void onPackagesRemoved(
-            @NonNull final UserHandle user, @NonNull final String... packages) {
-        int op = PackageUpdatedTask.OP_REMOVE;
-        FileLog.d(TAG, "package removed received " + TextUtils.join(",", packages));
-        enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packages));
-    }
-
-    @Override
-    public void onPackageAdded(@NonNull final String packageName, @NonNull final UserHandle user) {
-        int op = PackageUpdatedTask.OP_ADD;
-        enqueueModelUpdateTask(new PackageUpdatedTask(op, user, packageName));
-    }
-
-    @Override
-    public void onPackagesAvailable(@NonNull final String[] packageNames,
-            @NonNull final UserHandle user, final boolean replacing) {
-        enqueueModelUpdateTask(
-                new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, user, packageNames));
-    }
-
-    @Override
-    public void onPackagesUnavailable(@NonNull final String[] packageNames,
-            @NonNull final UserHandle user, final boolean replacing) {
-        if (!replacing) {
-            enqueueModelUpdateTask(new PackageUpdatedTask(
-                    PackageUpdatedTask.OP_UNAVAILABLE, user, packageNames));
-        }
-    }
-
-    @Override
-    public void onPackagesSuspended(
-            @NonNull final String[] packageNames, @NonNull final UserHandle user) {
-        enqueueModelUpdateTask(new PackageUpdatedTask(
-                PackageUpdatedTask.OP_SUSPEND, user, packageNames));
-    }
-
-    @Override
-    public void onPackagesUnsuspended(
-            @NonNull final String[] packageNames, @NonNull final UserHandle user) {
-        enqueueModelUpdateTask(new PackageUpdatedTask(
-                PackageUpdatedTask.OP_UNSUSPEND, user, packageNames));
-    }
-
-    @Override
-    public void onPackageLoadingProgressChanged(@NonNull final String packageName,
-            @NonNull final UserHandle user, final float progress) {
-        if (Utilities.ATLEAST_S) {
-            enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask(
-                    packageName, user, progress));
-        }
-    }
-
-    @Override
-    public void onShortcutsChanged(@NonNull final String packageName,
-            @NonNull final List<ShortcutInfo> shortcuts, @NonNull final UserHandle user) {
-        enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, true));
-    }
-
     /**
      * Called when the icon for an app changes, outside of package event
      */
@@ -265,7 +200,7 @@
             @NonNull final UserHandle user) {
         // Update the icon for the calendar package
         Context context = mApp.getContext();
-        onPackageChanged(packageName, user);
+        enqueueModelUpdateTask(new PackageUpdatedTask(OP_UPDATE, user, packageName));
 
         List<ShortcutInfo> pinnedShortcuts = new ShortcutRequest(context, user)
                 .forPackage(packageName).query(ShortcutRequest.PINNED);
@@ -430,7 +365,7 @@
                     MAIN_EXECUTOR.execute(cb::clearPendingBinds);
                 }
 
-                LauncherBinder launcherBinder = new LauncherBinder(
+                BaseLauncherBinder launcherBinder = new BaseLauncherBinder(
                         mApp, mBgDataModel, mBgAllAppsList, callbacksList);
                 if (bindDirectly) {
                     // Divide the set of loaded items into those that we are binding synchronously,
@@ -509,17 +444,41 @@
             @Override
             public void execute(@NonNull final LauncherAppState app,
                     @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+                IconCache iconCache = app.getIconCache();
                 final IntSet removedIds = new IntSet();
+                HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
+                boolean isAppArchived = PackageManagerHelper.INSTANCE.get(mApp.getContext())
+                        .isAppArchivedForUser(packageName, user);
                 synchronized (dataModel) {
+                    if (isAppArchived) {
+                        // Remove package icon cache entry for archived app in case of a session
+                        // failure.
+                        mApp.getIconCache().remove(
+                                new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                                user);
+                    }
+
                     for (ItemInfo info : dataModel.itemsIdMap) {
                         if (info instanceof WorkspaceItemInfo
                                 && ((WorkspaceItemInfo) info).hasPromiseIconUi()
                                 && user.equals(info.user)
-                                && info.getIntent() != null
-                                && TextUtils.equals(packageName, info.getIntent().getPackage())) {
-                            removedIds.add(info.id);
+                                && info.getIntent() != null) {
+                            if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+                                removedIds.add(info.id);
+                            }
+                            if (((WorkspaceItemInfo) info).isArchived()) {
+                                WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
+                                // Refresh icons on the workspace for archived apps.
+                                iconCache.getTitleAndIcon(workspaceItem,
+                                        workspaceItem.usingLowResIcon());
+                                archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
+                            }
                         }
                     }
+
+                    if (isAppArchived) {
+                        apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
+                    }
                 }
 
                 if (!removedIds.isEmpty()) {
@@ -527,6 +486,13 @@
                             ItemInfoMatcher.ofItemIds(removedIds),
                             "removed because install session failed");
                 }
+                if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
+                    bindUpdatedWorkspaceItems(
+                            archivedWorkspaceItemsToCacheRefresh.stream().toList());
+                }
+                if (isAppArchived) {
+                    bindApplicationsIfNeeded();
+                }
             }
         });
     }
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 78056e6..b503739 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -19,34 +19,26 @@
 import android.content.Context.MODE_PRIVATE
 import android.content.SharedPreferences
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
 import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
 import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
-import com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_DELAY
-import com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_END_SCALE_PERCENT
-import com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_ITERATIONS
-import com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_SCALE_EXPONENT
-import com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_START_SCALE_PERCENT
-import com.android.launcher3.config.FeatureFlags.LPNH_SLOP_PERCENTAGE
-import com.android.launcher3.config.FeatureFlags.LPNH_TIMEOUT_MS
 import com.android.launcher3.model.DeviceGridState
 import com.android.launcher3.pm.InstallSessionHelper
 import com.android.launcher3.provider.RestoreDbTask
+import com.android.launcher3.provider.RestoreDbTask.FIRST_LOAD_AFTER_RESTORE_KEY
 import com.android.launcher3.states.RotationHelper
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.SafeCloseable
 import com.android.launcher3.util.Themes
 
 /**
  * Use same context for shared preferences, so that we use a single cached instance
  *
  * TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
- * TODO(b/274501660): Fix ReorderWidgets#simpleReorder test before enabling
- *   isBootAwareStartupDataEnabled
  */
-class LauncherPrefs(private val encryptedContext: Context) {
+class LauncherPrefs(private val encryptedContext: Context) : SafeCloseable {
     private val deviceProtectedStorageContext =
         encryptedContext.createDeviceProtectedStorageContext()
 
@@ -57,22 +49,8 @@
     private val Item.encryptedPrefs
         get() = encryptedContext.getSharedPreferences(sharedPrefFile, MODE_PRIVATE)
 
-    // This call to `SharedPreferences` needs to be explicit rather than using `get` since doing so
-    // would result in a circular dependency between `isStartupDataMigrated` and `choosePreferences`
-    val isStartupDataMigrated: Boolean
-        get() =
-            bootAwarePrefs.getBoolean(
-                IS_STARTUP_DATA_MIGRATED.sharedPrefKey,
-                IS_STARTUP_DATA_MIGRATED.defaultValue
-            )
-
     private fun chooseSharedPreferences(item: Item): SharedPreferences =
-        if (
-            (moveStartupDataToDeviceProtectedStorageIsEnabled &&
-                item.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                isStartupDataMigrated) || item.encryptionType == EncryptionType.DEVICE_PROTECTED
-        )
-            bootAwarePrefs
+        if (item.encryptionType == EncryptionType.DEVICE_PROTECTED) bootAwarePrefs
         else item.encryptedPrefs
 
     /** Wrapper around `getInner` for a `ContextualItem` */
@@ -152,11 +130,7 @@
                 .toMutableMap()
 
         val bootAwareUpdates =
-            updates.filter {
-                (it.first.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
-                    it.first.encryptionType == EncryptionType.DEVICE_PROTECTED
-            }
+            updates.filter { it.first.encryptionType == EncryptionType.DEVICE_PROTECTED }
         if (bootAwareUpdates.isNotEmpty()) {
             updatesPerPrefFile[bootAwarePrefs] = bootAwareUpdates
         }
@@ -257,12 +231,7 @@
                 .groupBy { it.encryptedPrefs }
                 .toMutableMap()
 
-        val bootAwareUpdates =
-            items.filter {
-                (it.encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                    moveStartupDataToDeviceProtectedStorageIsEnabled) ||
-                    it.encryptionType == EncryptionType.DEVICE_PROTECTED
-            }
+        val bootAwareUpdates = items.filter { it.encryptionType == EncryptionType.DEVICE_PROTECTED }
         if (bootAwareUpdates.isNotEmpty()) {
             itemsPerFile[bootAwarePrefs] = bootAwareUpdates
         }
@@ -274,24 +243,9 @@
         }
     }
 
-    fun migrateStartupDataToDeviceProtectedStorage() {
-        if (!moveStartupDataToDeviceProtectedStorageIsEnabled) return
-
-        Log.d(
-            TAG,
-            "Migrating data to unencrypted shared preferences to enable preloading " +
-                "while the user is locked the next time the device reboots."
-        )
-
-        with(bootAwarePrefs.edit()) {
-            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.forEach { putValue(it, get(it)) }
-            putBoolean(IS_STARTUP_DATA_MIGRATED.sharedPrefKey, true)
-            apply()
-        }
-    }
+    override fun close() {}
 
     companion object {
-        private const val TAG = "LauncherPrefs"
         @VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
 
         @JvmField var INSTANCE = MainThreadInitializedObject { LauncherPrefs(it) }
@@ -301,94 +255,20 @@
         const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
         const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
         @JvmField
-        val ICON_STATE =
-            nonRestorableItem(
-                    "pref_icon_shape_path",
-                "",
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+        val ICON_STATE = nonRestorableItem("pref_icon_shape_path", "", EncryptionType.ENCRYPTED)
+
         @JvmField
-        val ALL_APPS_OVERVIEW_THRESHOLD =
-            nonRestorableItem(
-                    "pref_all_apps_overview_threshold",
-                180,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+        val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
         @JvmField
-        val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
-            nonRestorableItem(
-                "pref_long_press_nav_handle_slop_percentage",
-                        LPNH_SLOP_PERCENTAGE.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_timeout_ms",
-                        LPNH_TIMEOUT_MS.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_haptic_hint_start_scale_percent",
-                        LPNH_HAPTIC_HINT_START_SCALE_PERCENT.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_haptic_hint_end_scale_percent",
-                        LPNH_HAPTIC_HINT_END_SCALE_PERCENT.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_haptic_hint_scale_exponent",
-                        LPNH_HAPTIC_HINT_SCALE_EXPONENT.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_haptic_hint_iterations",
-                        LPNH_HAPTIC_HINT_ITERATIONS.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY =
-                nonRestorableItem(
-                        "pref_long_press_nav_handle_haptic_hint_delay",
-                        LPNH_HAPTIC_HINT_DELAY.get(),
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val PRIVATE_SPACE_APPS =
-                nonRestorableItem(
-                        "pref_private_space_apps",
-                        0,
-                        EncryptionType.MOVE_TO_DEVICE_PROTECTED
-                )
-        @JvmField
-        val THEMED_ICONS =
-            backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+        val THEMED_ICONS = backedUpItem(Themes.KEY_THEMED_ICONS, false, EncryptionType.ENCRYPTED)
         @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
         @JvmField val WORK_EDU_STEP = backedUpItem("showed_work_profile_edu", 0)
         @JvmField
         val WORKSPACE_SIZE =
-            backedUpItem(
-                DeviceGridState.KEY_WORKSPACE_SIZE,
-                "",
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+            backedUpItem(DeviceGridState.KEY_WORKSPACE_SIZE, "", EncryptionType.ENCRYPTED)
         @JvmField
         val HOTSEAT_COUNT =
-            backedUpItem(
-                DeviceGridState.KEY_HOTSEAT_COUNT,
-                -1,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
+            backedUpItem(DeviceGridState.KEY_HOTSEAT_COUNT, -1, EncryptionType.ENCRYPTED)
         @JvmField
         val TASKBAR_PINNING =
             backedUpItem(TASKBAR_PINNING_KEY, false, EncryptionType.DEVICE_PROTECTED)
@@ -398,11 +278,10 @@
             backedUpItem(
                 DeviceGridState.KEY_DEVICE_TYPE,
                 InvariantDeviceProfile.TYPE_PHONE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.ENCRYPTED
             )
         @JvmField
-        val DB_FILE =
-            backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+        val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", EncryptionType.ENCRYPTED)
         @JvmField
         val SHOULD_SHOW_SMARTSPACE =
             backedUpItem(
@@ -415,8 +294,11 @@
             backedUpItem(
                 RestoreDbTask.RESTORED_DEVICE_TYPE,
                 InvariantDeviceProfile.TYPE_PHONE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.ENCRYPTED
             )
+        @JvmField
+        val IS_FIRST_LOAD_AFTER_RESTORE =
+            nonRestorableItem(FIRST_LOAD_AFTER_RESTORE_KEY, false, EncryptionType.ENCRYPTED)
         @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
         @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
         @JvmField
@@ -425,7 +307,7 @@
                 "idp_grid_name",
                 isBackedUp = true,
                 defaultValue = null,
-                encryptionType = EncryptionType.MOVE_TO_DEVICE_PROTECTED,
+                encryptionType = EncryptionType.ENCRYPTED,
                 type = String::class.java
             )
         @JvmField
@@ -433,14 +315,6 @@
             backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
                 RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
             }
-        @JvmField
-        val IS_STARTUP_DATA_MIGRATED =
-            ConstantItem(
-                "is_startup_data_boot_aware",
-                isBackedUp = false,
-                defaultValue = false,
-                encryptionType = EncryptionType.DEVICE_PROTECTED
-            )
 
         // Preferences for widget configurations
         @JvmField
@@ -505,12 +379,6 @@
     }
 }
 
-// It is a var because the unit tests are setting this to true so they can run.
-var moveStartupDataToDeviceProtectedStorageIsEnabled: Boolean =
-    com.android.launcher3.config.FeatureFlags.MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE.get()
-
-private val ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE: MutableSet<ConstantItem<*>> = mutableSetOf()
-
 abstract class Item {
     abstract val sharedPrefKey: String
     abstract val isBackedUp: Boolean
@@ -530,14 +398,6 @@
     // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
     override val type: Class<out T> = defaultValue!!::class.java
 ) : Item() {
-    init {
-        if (
-            encryptionType == EncryptionType.MOVE_TO_DEVICE_PROTECTED &&
-                moveStartupDataToDeviceProtectedStorageIsEnabled
-        ) {
-            ITEMS_TO_MOVE_TO_DEVICE_PROTECTED_STORAGE.add(this)
-        }
-    }
 
     fun get(c: Context): T = LauncherPrefs.get(c).get(this)
 }
@@ -564,5 +424,4 @@
 enum class EncryptionType {
     ENCRYPTED,
     DEVICE_PROTECTED,
-    MOVE_TO_DEVICE_PROTECTED
 }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4e0ba62..6e2d357 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -48,11 +48,11 @@
      */
     @Override
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
-        LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
-        if (appState == null || !appState.getModel().isModelLoaded()) {
-            return;
-        }
-        appState.getModel().dumpState("", fd, writer, args);
+        LauncherAppState.INSTANCE.executeIfCreated(appState -> {
+            if (appState.getModel().isModelLoaded()) {
+                appState.getModel().dumpState("", fd, writer, args);
+            }
+        });
     }
 
     @Override
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 1592154..7176733 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -2,11 +2,9 @@
 
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.ViewDebug;
 import android.view.WindowInsets;
@@ -112,15 +110,13 @@
         mSysUiScrim.setSize(r - l, b - t);
     }
 
-    @TargetApi(Build.VERSION_CODES.Q)
     public void setForceHideBackArrow(boolean forceHideBackArrow) {
         this.mForceHideBackArrow = forceHideBackArrow;
         setDisallowBackGesture(mDisallowBackGesture);
     }
 
-    @TargetApi(Build.VERSION_CODES.Q)
     public void setDisallowBackGesture(boolean disallowBackGesture) {
-        if (!Utilities.ATLEAST_Q || SEPARATE_RECENTS_ACTIVITY.get()) {
+        if (SEPARATE_RECENTS_ACTIVITY.get()) {
             return;
         }
         mDisallowBackGesture = disallowBackGesture;
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 34ebaf2..87ac193 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -139,6 +139,11 @@
         public static final int ITEM_TYPE_SEARCH_ACTION = 9;
 
         /**
+         * Private space install app button.
+         */
+        public static final int ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON = 11;
+
+        /**
          * The custom icon bitmap.
          * <P>Type: BLOB</P>
          */
@@ -178,6 +183,7 @@
         public static final int CONTAINER_SHORTCUTS = -107;
         public static final int CONTAINER_SETTINGS = -108;
         public static final int CONTAINER_TASKSWITCHER = -109;
+        public static final int CONTAINER_PRIVATESPACE = -110;
 
         // Represents any of the extended containers implemented in non-AOSP variants.
         public static final int EXTENDED_CONTAINERS = -200;
@@ -206,6 +212,8 @@
                 case ITEM_TYPE_TASK: return "TASK";
                 case ITEM_TYPE_QSB: return "QSB";
                 case ITEM_TYPE_APP_PAIR: return "APP_PAIR";
+                case ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON:
+                    return "PRIVATE_SPACE_INSTALL_APP_BUTTON";
                 default: return String.valueOf(type);
             }
         }
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index d2ea7cc..3bdd863 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -17,6 +17,7 @@
 
 import static com.android.app.animation.Interpolators.ACCELERATE_2;
 import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
@@ -423,15 +424,33 @@
         return TestProtocol.stateOrdinalToString(ordinal);
     }
 
-    public void onBackPressed(Launcher launcher) {
+    /** Called when predictive back gesture is started. */
+    public void onBackStarted(Launcher launcher) {}
+
+    /**
+     * Called when back action is invoked. This can happen when:
+     * 1. back button is pressed in 3-button navigation.
+     * 2. when back is committed during back swiped (predictive or non-predictive).
+     * 3. when we programmatically perform back action.
+     */
+    public void onBackInvoked(Launcher launcher) {
         if (this != NORMAL) {
             StateManager<LauncherState> lsm = launcher.getStateManager();
             LauncherState lastState = lsm.getLastState();
-            lsm.goToState(lastState);
+            lsm.goToState(lastState, forEndCallback(this::onBackAnimationCompleted));
         }
     }
 
     /**
+     * To be called if back animation is completed in a launcher state.
+     *
+     * @param success whether back animation was successful or canceled.
+     */
+    protected void onBackAnimationCompleted(boolean success) {
+        // Do nothing. To be overridden by child class.
+    }
+
+    /**
      * Find {@link StateManager} and target {@link LauncherState} to handle back progress in
      * predictive back gesture.
      */
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 5172999..f582be0 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -3,7 +3,6 @@
 import android.annotation.TargetApi
 import android.os.Build
 import android.os.Trace
-import android.view.ViewTreeObserver.OnDrawListener
 import androidx.annotation.UiThread
 import com.android.launcher3.LauncherConstants.TraceEvents
 import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
@@ -18,7 +17,6 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.popup.PopupContainerWithArrow
 import com.android.launcher3.util.ComponentKey
-import com.android.launcher3.util.Executors
 import com.android.launcher3.util.IntArray as LIntArray
 import com.android.launcher3.util.IntSet as LIntSet
 import com.android.launcher3.util.PackageUserKey
@@ -65,7 +63,8 @@
         launcher.dragController.cancelDrag()
         launcher.workspace.clearDropTargets()
         launcher.workspace.removeAllWorkspaceScreens()
-        launcher.appWidgetHolder.clearViews()
+        // Avoid clearing the widget update listeners for staying up-to-date with widget info
+        launcher.appWidgetHolder.clearWidgetViews()
         launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
         TraceHelper.INSTANCE.endSection()
     }
@@ -74,14 +73,19 @@
     override fun onInitialBindComplete(
         boundPages: LIntSet,
         pendingTasks: RunnableList,
+        onCompleteSignal: RunnableList,
         workspaceItemCount: Int,
         isBindSync: Boolean
     ) {
+        if (Utilities.ATLEAST_S) {
+            Trace.endAsyncSection(
+                TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
+                TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
+            )
+        }
         synchronouslyBoundPages = boundPages
         pagesToBindSynchronously = LIntSet()
         clearPendingBinds()
-        val executor = ViewOnDrawExecutor(pendingTasks)
-        pendingExecutor = executor
         if (!launcher.isInState(LauncherState.ALL_APPS)) {
             launcher.appsView.appsStore.enableDeferUpdates(AllAppsStore.DEFER_UPDATES_NEXT_DRAW)
             pendingTasks.add {
@@ -90,24 +94,22 @@
                 )
             }
         }
-        executor.onLoadAnimationCompleted()
-        executor.attachTo(launcher)
-        if (Utilities.ATLEAST_S) {
-            Trace.endAsyncSection(
-                TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
-                TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
-            )
-        }
-        launcher.bindComplete(workspaceItemCount, isBindSync)
-        launcher.rootView.viewTreeObserver.addOnDrawListener(
-            object : OnDrawListener {
-                override fun onDraw() {
-                    Executors.MAIN_EXECUTOR.handler.postAtFrontOfQueue {
-                        launcher.rootView.getViewTreeObserver().removeOnDrawListener(this)
-                    }
+        val executor =
+            ViewOnDrawExecutor(pendingTasks) {
+                if (pendingExecutor == it) {
+                    pendingExecutor = null
                 }
             }
-        )
+        pendingExecutor = executor
+
+        if (Flags.enableWorkspaceInflation()) {
+            // Finish the executor as soon as the pending inflation is completed
+            onCompleteSignal.add(executor::markCompleted)
+        } else {
+            // Pending executor is already completed, wait until first draw to run the tasks
+            executor.attachTo(launcher)
+        }
+        launcher.bindComplete(workspaceItemCount, isBindSync)
     }
 
     /**
@@ -139,7 +141,7 @@
         launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
         TraceHelper.INSTANCE.endSection()
         launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
-        launcher.workspace.pageIndicator.setAreScreensBinding(false, deviceProfile.isTwoPanels)
+        launcher.workspace.pageIndicator.setPauseScroll(/*pause=*/ false, deviceProfile.isTwoPanels)
     }
 
     /**
@@ -178,7 +180,10 @@
         val hadWorkApps = launcher.appsView.shouldShowTabs()
         launcher.appsView.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
         PopupContainerWithArrow.dismissInvalidPopup(launcher)
-        if (hadWorkApps != launcher.appsView.shouldShowTabs()) {
+        if (
+            hadWorkApps != launcher.appsView.shouldShowTabs() &&
+                launcher.stateManager.state == LauncherState.ALL_APPS
+        ) {
             launcher.stateManager.goToState(LauncherState.NORMAL)
         }
     }
@@ -303,8 +308,8 @@
     }
 
     override fun bindScreens(orderedScreenIds: LIntArray) {
-        launcher.workspace.pageIndicator.setAreScreensBinding(
-            true,
+        launcher.workspace.pageIndicator.setPauseScroll(
+            /*pause=*/ true,
             launcher.deviceProfile.isTwoPanels
         )
         val firstScreenPosition = 0
@@ -413,4 +418,6 @@
     }
 
     fun getIsFirstPagePinnedItemEnabled(): Boolean = isFirstPagePinnedItemEnabled
+
+    override fun getItemInflater() = launcher.itemInflater
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index f355ae7..1c23644 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -118,7 +118,8 @@
     private float mTotalMotion;
     // Used in special cases where the fling checks can be relaxed for an intentional gesture
     private boolean mAllowEasyFling;
-    protected PagedOrientationHandler mOrientationHandler = PagedOrientationHandler.PORTRAIT;
+    private PagedOrientationHandler mOrientationHandler =
+            PagedOrientationHandler.DEFAULT;
 
     private final ArrayList<Runnable> mOnPageScrollsInitializedCallbacks = new ArrayList<>();
 
@@ -231,6 +232,14 @@
         return getChildAt(index);
     }
 
+    protected PagedOrientationHandler getPagedOrientationHandler() {
+        return mOrientationHandler;
+    }
+
+    protected void setOrientationHandler(PagedOrientationHandler orientationHandler) {
+        this.mOrientationHandler = orientationHandler;
+    }
+
     /**
      * Updates the scroll of the current page immediately to its final scroll position.  We use this
      * in CustomizePagedView to allow tabs to share the same PagedView while resetting the scroll of
@@ -628,6 +637,11 @@
         mMinFlingVelocity = res.getDimensionPixelSize(R.dimen.min_fling_velocity);
         mMinSnapVelocity = res.getDimensionPixelSize(R.dimen.min_page_snap_velocity);
         mPageSnapAnimationDuration = res.getInteger(R.integer.config_pageSnapAnimationDuration);
+        onVelocityValuesUpdated();
+    }
+
+    protected void onVelocityValuesUpdated() {
+        // Overridden in RecentsView
     }
 
     @Override
@@ -812,7 +826,9 @@
                 // or right edge for RTL.
                 final int pageScroll =
                         mIsRtl ? childPrimaryEnd - scrollOffsetEnd : childStart - scrollOffsetStart;
-                if (outPageScrolls[i] != pageScroll) {
+                // If there's more than one panel, only update scroll on leftmost panel.
+                if (outPageScrolls[i] != pageScroll
+                        && (panelCount <= 1 || i == getLeftmostVisiblePageForIndex(i))) {
                     pageScrollChanged = true;
                     outPageScrolls[i] = pageScroll;
                 }
@@ -828,7 +844,7 @@
 
         if (panelCount > 1) {
             for (int i = 0; i < childCount; i++) {
-                // In case we have multiple panels, always use left most panel's page scroll for all
+                // In case we have multiple panels, always use leftmost panel's page scroll for all
                 // panels on the screen.
                 int adjustedScroll = outPageScrolls[getLeftmostVisiblePageForIndex(i)];
                 if (outPageScrolls[i] != adjustedScroll) {
@@ -1126,7 +1142,7 @@
             mEdgeGlowLeft.onPullDistance(0f, 1f - displacement);
         }
         if (!mEdgeGlowRight.isFinished()) {
-            mEdgeGlowRight.onPullDistance(0f, displacement);
+            mEdgeGlowRight.onPullDistance(0f, displacement, ev);
         }
     }
 
@@ -1306,10 +1322,10 @@
                     int consumed = 0;
                     if (delta < 0 && mEdgeGlowRight.getDistance() != 0f) {
                         consumed = Math.round(size *
-                                mEdgeGlowRight.onPullDistance(delta / size, displacement));
+                                mEdgeGlowRight.onPullDistance(delta / size, displacement, ev));
                     } else if (delta > 0 && mEdgeGlowLeft.getDistance() != 0f) {
                         consumed = Math.round(-size *
-                                mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement));
+                                mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement, ev));
                     }
                     delta -= consumed;
                 }
@@ -1327,14 +1343,14 @@
                         final float pulledToX = oldScroll + delta;
 
                         if (pulledToX < mMinScroll) {
-                            mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement);
+                            mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement, ev);
                             if (!mEdgeGlowRight.isFinished()) {
-                                mEdgeGlowRight.onRelease();
+                                mEdgeGlowRight.onRelease(ev);
                             }
                         } else if (pulledToX > mMaxScroll) {
-                            mEdgeGlowRight.onPullDistance(delta / size, displacement);
+                            mEdgeGlowRight.onPullDistance(delta / size, displacement, ev);
                             if (!mEdgeGlowLeft.isFinished()) {
-                                mEdgeGlowLeft.onRelease();
+                                mEdgeGlowLeft.onRelease(ev);
                             }
                         }
 
@@ -1342,7 +1358,6 @@
                             postInvalidateOnAnimation();
                         }
                     }
-
                 } else {
                     awakenScrollBars();
                 }
@@ -1442,10 +1457,11 @@
                     }
                     invalidate();
                 }
+                mEdgeGlowLeft.onFlingVelocity(velocity);
+                mEdgeGlowRight.onFlingVelocity(velocity);
             }
-
-            mEdgeGlowLeft.onRelease();
-            mEdgeGlowRight.onRelease();
+            mEdgeGlowLeft.onRelease(ev);
+            mEdgeGlowRight.onRelease(ev);
             // End any intermediate reordering states
             resetTouchState();
             break;
@@ -1454,8 +1470,8 @@
             if (mIsBeingDragged) {
                 runOnPageScrollsInitialized(this::snapToDestination);
             }
-            mEdgeGlowLeft.onRelease();
-            mEdgeGlowRight.onRelease();
+            mEdgeGlowLeft.onRelease(ev);
+            mEdgeGlowRight.onRelease(ev);
             resetTouchState();
             break;
 
@@ -1573,7 +1589,7 @@
     @Override
     public void requestChildFocus(View child, View focused) {
         super.requestChildFocus(child, focused);
-        if (!shouldHandleRequestChildFocus()) {
+        if (!shouldHandleRequestChildFocus(child)) {
             return;
         }
         // In case the device is controlled by a controller, mCurrentPage isn't updated properly
@@ -1589,7 +1605,7 @@
         }
     }
 
-    protected boolean shouldHandleRequestChildFocus() {
+    protected boolean shouldHandleRequestChildFocus(View child) {
         return true;
     }
 
@@ -1643,7 +1659,7 @@
     }
 
     protected void snapToDestination() {
-        snapToPage(getDestinationPage(), mPageSnapAnimationDuration);
+        snapToPage(getDestinationPage(), getSnapAnimationDuration());
     }
 
     // We want the duration of the page snap animation to be influenced by the distance that
@@ -1667,7 +1683,7 @@
         if (Math.abs(velocity) < mMinFlingVelocity) {
             // If the velocity is low enough, then treat this more as an automatic page advance
             // as opposed to an apparent physical response to flinging
-            return snapToPage(whichPage, mPageSnapAnimationDuration);
+            return snapToPage(whichPage, getSnapAnimationDuration());
         }
 
         // Here we compute a "distance" that will be used in the computation of the overall
@@ -1689,12 +1705,16 @@
         return snapToPage(whichPage, delta, duration);
     }
 
+    protected int getSnapAnimationDuration() {
+        return mPageSnapAnimationDuration;
+    }
+
     public boolean snapToPage(int whichPage) {
-        return snapToPage(whichPage, mPageSnapAnimationDuration);
+        return snapToPage(whichPage, getSnapAnimationDuration());
     }
 
     public boolean snapToPageImmediately(int whichPage) {
-        return snapToPage(whichPage, mPageSnapAnimationDuration, true);
+        return snapToPage(whichPage, getSnapAnimationDuration(), true);
     }
 
     public boolean snapToPage(int whichPage, int duration) {
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 2dd610cb..0a4fb73 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -34,6 +34,8 @@
 import android.view.View;
 import android.widget.Toast;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.logging.FileLog;
@@ -43,6 +45,7 @@
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
@@ -155,6 +158,9 @@
             }
             return INVALID;
         } else if (info.isPredictedItem()) {
+            if (Flags.enableShortcutDontSuggestApp()) {
+                return INVALID;
+            }
             return DISMISS_PREDICTION;
         }
 
@@ -173,6 +179,10 @@
         if (uninstallDisabled) {
             return INVALID;
         }
+        if (Flags.enablePrivateSpace() && UserCache.getInstance(getContext()).getUserInfo(
+                info.user).isPrivate()) {
+            return INVALID;
+        }
 
         if (info instanceof ItemInfoWithIcon) {
             ItemInfoWithIcon iconInfo = (ItemInfoWithIcon) info;
@@ -181,7 +191,7 @@
                 return INVALID;
             }
         }
-        if (getUninstallTarget(info) == null) {
+        if (getUninstallTarget(getContext(), info) == null) {
             return INVALID;
         }
         return UNINSTALL;
@@ -190,7 +200,7 @@
     /**
      * @return the component name that should be uninstalled or null.
      */
-    private ComponentName getUninstallTarget(ItemInfo item) {
+    public static ComponentName getUninstallTarget(Context context, ItemInfo item) {
         Intent intent = null;
         UserHandle user = null;
         if (item != null &&
@@ -199,7 +209,7 @@
             user = item.user;
         }
         if (intent != null) {
-            LauncherActivityInfo info = getContext().getSystemService(LauncherApps.class)
+            LauncherActivityInfo info = context.getSystemService(LauncherApps.class)
                     .resolveActivity(intent, user);
             if (info != null
                     && (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
@@ -277,32 +287,41 @@
             if (FeatureFlags.ENABLE_DISMISS_PREDICTION_UNDO.get()) {
                 CharSequence announcement = getContext().getString(R.string.item_removed);
                 mDropTargetHandler
-                        .dismissPrediction(announcement, () -> {}, () -> {
-                    mStatsLogManager.logger()
-                            .withInstanceId(instanceId)
-                            .withItemInfo(info)
-                            .log(LAUNCHER_DISMISS_PREDICTION_UNDO);
-                });
+                        .dismissPrediction(announcement, () -> {
+                        }, () -> {
+                            mStatsLogManager.logger()
+                                    .withInstanceId(instanceId)
+                                    .withItemInfo(info)
+                                    .log(LAUNCHER_DISMISS_PREDICTION_UNDO);
+                        });
             }
             return null;
         }
 
-        ComponentName cn = getUninstallTarget(info);
+        return performUninstall(getContext(), getUninstallTarget(getContext(), info), info);
+    }
+
+    /**
+     * Performs uninstall and returns the target component for the {@link ItemInfo} or null if
+     * the uninstall was not performed.
+     */
+    public static ComponentName performUninstall(Context context, @Nullable ComponentName cn,
+            ItemInfo info) {
         if (cn == null) {
             // System applications cannot be installed. For now, show a toast explaining that.
             // We may give them the option of disabling apps this way.
             Toast.makeText(
-                    getContext(),
+                    context,
                     R.string.uninstall_system_app_text,
                     Toast.LENGTH_SHORT
-                ).show();
+            ).show();
             return null;
         }
         try {
-            Intent i = Intent.parseUri(getContext().getString(R.string.delete_package_intent), 0)
+            Intent i = Intent.parseUri(context.getString(R.string.delete_package_intent), 0)
                     .setData(Uri.fromParts("package", cn.getPackageName(), cn.getClassName()))
                     .putExtra(Intent.EXTRA_USER, info.user);
-            getContext().startActivity(i);
+            context.startActivity(i);
             FileLog.d(TAG, "start uninstall activity " + cn.getPackageName());
             return cn;
         } catch (URISyntaxException e) {
@@ -343,7 +362,7 @@
 
         public void onLauncherResume() {
             // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
-            if (new PackageManagerHelper(mContext).getApplicationInfo(mPackageName,
+            if (PackageManagerHelper.INSTANCE.get(mContext).getApplicationInfo(mPackageName,
                     mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
                 mDragObject.dragSource = mOriginal;
                 mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index d460ba8..6168e41 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -30,6 +30,7 @@
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.Executors;
 
 import java.util.Locale;
@@ -51,13 +52,13 @@
 
     @WorkerThread
     private static void processIntent(Context context, Intent intent) {
-        if (!isEnabled(context)) {
+        UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
+        if (!isEnabled(context, user)) {
             // User has decided to not add icons on homescreen.
             return;
         }
 
         SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
-        UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
         if (!PackageInstaller.ACTION_SESSION_COMMITTED.equals(intent.getAction())
                 || info == null || user == null) {
             // Invalid intent.
@@ -92,7 +93,17 @@
                 .queueItem(info.getAppPackageName(), user);
     }
 
-    public static boolean isEnabled(Context context) {
+    /**
+     * Returns whether adding Installed App Icons to home screen is allowed or not.
+     * Not allowed when:
+     * - User belongs to {@link com.android.launcher3.util.UserIconInfo.TYPE_PRIVATE} or
+     * - Home Settings preference to add App Icons on Home Screen is set as disabled
+     */
+    public static boolean isEnabled(Context context, UserHandle user) {
+        if (Flags.privateSpaceRestrictItemDrag() && user != null
+                && UserCache.getInstance(context).getUserInfo(user).isPrivate()) {
+            return false;
+        }
         return LauncherPrefs.getPrefs(context).getBoolean(ADD_ICON_PREFERENCE_KEY, true);
     }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index e0f6101..2b886e4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -121,15 +121,6 @@
     public static final String[] EMPTY_STRING_ARRAY = new String[0];
     public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
 
-    @ChecksSdkIntAtLeast(api = VERSION_CODES.P)
-    public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
-
-    @ChecksSdkIntAtLeast(api = VERSION_CODES.Q)
-    public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
-
-    @ChecksSdkIntAtLeast(api = VERSION_CODES.R)
-    public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
-
     @ChecksSdkIntAtLeast(api = VERSION_CODES.S)
     public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
 
diff --git a/src/com/android/launcher3/UtilitiesKt.kt b/src/com/android/launcher3/UtilitiesKt.kt
new file mode 100644
index 0000000..a207d57
--- /dev/null
+++ b/src/com/android/launcher3/UtilitiesKt.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3
+
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewParent
+
+object UtilitiesKt {
+
+    /**
+     * Modify [ViewGroup]'s attribute with type [T]. The overridden attribute is saved by calling
+     * [View.setTag] and can be later restored by [View.getTag].
+     *
+     * @param <T> type of [ViewGroup] attribute. For example, [T] is [Boolean] if modifying
+     *   [ViewGroup.setClipChildren]
+     */
+    abstract class ViewGroupAttrModifier<T>(
+        private val targetAttrValue: T,
+        private val tagKey: Int
+    ) {
+        /**
+         * If [targetAttrValue] is different from existing view attribute returned from
+         * [getAttribute], this method will save existing attribute by calling [ViewGroup.setTag].
+         * Then call [setAttribute] to set attribute with [targetAttrValue].
+         */
+        fun saveAndChangeAttribute(viewGroup: ViewGroup) {
+            val oldAttrValue = getAttribute(viewGroup)
+            if (oldAttrValue !== targetAttrValue) {
+                viewGroup.setTag(tagKey, oldAttrValue)
+                setAttribute(viewGroup, targetAttrValue)
+            }
+        }
+
+        /** Restore saved attribute in [saveAndChangeAttribute] by calling [ViewGroup.getTag]. */
+        @Suppress("UNCHECKED_CAST")
+        fun restoreAttribute(viewGroup: ViewGroup) {
+            val oldAttrValue: T = viewGroup.getTag(tagKey) as T ?: return
+            setAttribute(viewGroup, oldAttrValue)
+            viewGroup.setTag(tagKey, null)
+        }
+
+        /** Subclass will override this method to decide how to get [ViewGroup] attribute. */
+        abstract fun getAttribute(viewGroup: ViewGroup): T
+
+        /** Subclass will override this method to decide how to set [ViewGroup] attribute. */
+        abstract fun setAttribute(viewGroup: ViewGroup, attr: T)
+    }
+
+    /** [ViewGroupAttrModifier] to call [ViewGroup.setClipChildren] to false. */
+    @JvmField
+    val CLIP_CHILDREN_FALSE_MODIFIER: ViewGroupAttrModifier<Boolean> =
+        object : ViewGroupAttrModifier<Boolean>(false, R.id.saved_clip_children_tag_id) {
+            override fun getAttribute(viewGroup: ViewGroup): Boolean {
+                return viewGroup.clipChildren
+            }
+
+            override fun setAttribute(viewGroup: ViewGroup, clipChildren: Boolean) {
+                viewGroup.clipChildren = clipChildren
+            }
+        }
+
+    /** [ViewGroupAttrModifier] to call [ViewGroup.setClipToPadding] to false. */
+    @JvmField
+    val CLIP_TO_PADDING_FALSE_MODIFIER: ViewGroupAttrModifier<Boolean> =
+        object : ViewGroupAttrModifier<Boolean>(false, R.id.saved_clip_to_padding_tag_id) {
+            override fun getAttribute(viewGroup: ViewGroup): Boolean {
+                return viewGroup.clipToPadding
+            }
+
+            override fun setAttribute(viewGroup: ViewGroup, clipToPadding: Boolean) {
+                viewGroup.clipToPadding = clipToPadding
+            }
+        }
+
+    /**
+     * Recursively call [ViewGroupAttrModifier.saveAndChangeAttribute] from [View] to its parent
+     * (direct or indirect) inclusive.
+     *
+     * [ViewGroupAttrModifier.saveAndChangeAttribute] will save the existing attribute value on each
+     * view with [View.setTag], which can be restored in [restoreAttributesOnViewTree].
+     *
+     * Note that if parent is null or not a parent of the view, this method will be applied all the
+     * way to root view.
+     *
+     * @param v child view
+     * @param parent direct or indirect parent of child view
+     * @param modifiers list of [ViewGroupAttrModifier] to modify view attribute
+     */
+    @JvmStatic
+    fun modifyAttributesOnViewTree(
+        v: View?,
+        parent: ViewParent?,
+        vararg modifiers: ViewGroupAttrModifier<*>
+    ) {
+        if (v == null) {
+            return
+        }
+        if (v is ViewGroup) {
+            for (modifier in modifiers) {
+                modifier.saveAndChangeAttribute(v)
+            }
+        }
+        if (v === parent) {
+            return
+        }
+        if (v.parent is View) {
+            modifyAttributesOnViewTree(v.parent as View, parent, *modifiers)
+        }
+    }
+
+    /**
+     * Recursively call [ViewGroupAttrModifier.restoreAttribute]} to restore view attributes
+     * previously saved in [ViewGroupAttrModifier.saveAndChangeAttribute] on view to its parent
+     * (direct or indirect) inclusive.
+     *
+     * Note that if parent is null or not a parent of the view, this method will be applied all the
+     * way to root view.
+     *
+     * @param v child view
+     * @param parent direct or indirect parent of child view
+     * @param modifiers list of [ViewGroupAttrModifier] to restore view attributes
+     */
+    @JvmStatic
+    fun restoreAttributesOnViewTree(
+        v: View?,
+        parent: ViewParent?,
+        vararg modifiers: ViewGroupAttrModifier<*>
+    ) {
+        if (v == null) {
+            return
+        }
+        if (v is ViewGroup) {
+            for (modifier in modifiers) {
+                modifier.restoreAttribute(v)
+            }
+        }
+        if (v === parent) {
+            return
+        }
+        if (v.parent is View) {
+            restoreAttributesOnViewTree(v.parent as View, parent, *modifiers)
+        }
+    }
+}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index be4168d..0fc3211 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -16,8 +16,9 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
 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.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.LauncherState.FLAG_MULTI_PAGE;
@@ -96,10 +97,10 @@
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.statemanager.StateManager;
@@ -127,8 +128,8 @@
 import com.android.launcher3.widget.WidgetManagerHelper;
 import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
 import com.android.launcher3.widget.util.WidgetSizes;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -145,7 +146,7 @@
  * @param <T> Class that extends View and PageIndicator
  */
 public class Workspace<T extends View & PageIndicator> extends PagedView<T>
-        implements DropTarget, DragSource, View.OnTouchListener,
+        implements DropTarget, DragSource, View.OnTouchListener, CellLayoutContainer,
         DragController.DragListener, Insettable, StateHandler<LauncherState>,
         WorkspaceLayoutManager, LauncherBindableItemsContainer, LauncherOverlayCallbacks {
 
@@ -242,6 +243,8 @@
     public static final int REORDER_TIMEOUT = 650;
     protected final Alarm mReorderAlarm = new Alarm();
     private PreviewBackground mFolderCreateBg;
+    /** The underlying view that we are dragging something over. */
+    private View mDragOverView = null;
     private FolderIcon mDragOverFolderIcon = null;
     private boolean mCreateUserFolderOnDrop = false;
     private boolean mAddToExistingFolderOnDrop = false;
@@ -513,11 +516,6 @@
         return !FOLDABLE_SINGLE_PAGE.get() && mLauncher.mDeviceProfile.isTwoPanels;
     }
 
-    @Override
-    public int getPanelCount() {
-        return isTwoPanelEnabled() ? 2 : super.getPanelCount();
-    }
-
     public void deferRemoveExtraEmptyScreen() {
         mDeferRemoveExtraEmptyScreen = true;
     }
@@ -685,6 +683,7 @@
             newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate(
                     R.layout.workspace_screen, this, false /* attachToRoot */);
         }
+        newScreen.setCellLayoutContainer(this);
 
         mWorkspaceScreens.put(screenId, newScreen);
         mScreenOrder.add(insertIndex, screenId);
@@ -951,7 +950,8 @@
         return mWorkspaceScreens.get(screenId);
     }
 
-    public int getIdForScreen(CellLayout layout) {
+    @Override
+    public int getCellLayoutId(CellLayout layout) {
         int index = mWorkspaceScreens.indexOfValue(layout);
         if (index != -1) {
             return mWorkspaceScreens.keyAt(index);
@@ -963,6 +963,16 @@
         return indexOfChild(mWorkspaceScreens.get(screenId));
     }
 
+    @Override
+    public int getCellLayoutIndex(CellLayout cellLayout) {
+        return indexOfChild(mWorkspaceScreens.get(getCellLayoutId(cellLayout)));
+    }
+
+    @Override
+    public int getPanelCount() {
+        return isTwoPanelEnabled() ? 2 : super.getPanelCount();
+    }
+
     public IntSet getCurrentPageScreenIds() {
         return IntSet.wrap(getScreenIdForPageIndex(getCurrentPage()));
     }
@@ -1003,7 +1013,7 @@
         if (!isTwoPanelEnabled()) {
             return null;
         }
-        int screenId = getIdForScreen(cellLayout);
+        int screenId = getCellLayoutId(cellLayout);
         if (screenId == -1) {
             return null;
         }
@@ -1232,7 +1242,7 @@
         mLauncher.onPageEndTransition();
     }
 
-    public void setLauncherOverlay(LauncherOverlay overlay) {
+    public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
         final EdgeEffectCompat newEffect;
         if (overlay == null) {
             newEffect = new EdgeEffectCompat(getContext());
@@ -1631,9 +1641,15 @@
             mDragController.addDragListener(
                     new AccessibleDragListenerAdapter(this, WorkspaceAccessibilityHelper::new) {
                         @Override
-                        protected void enableAccessibleDrag(boolean enable) {
-                            super.enableAccessibleDrag(enable);
+                        protected void enableAccessibleDrag(boolean enable,
+                                @Nullable DragObject dragObject) {
+                            super.enableAccessibleDrag(enable, dragObject);
                             setEnableForLayout(mLauncher.getHotseat(), enable);
+                            if (enable && dragObject != null
+                                    && dragObject.dragInfo instanceof LauncherAppWidgetInfo) {
+                                mLauncher.getHotseat().setImportantForAccessibility(
+                                        IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+                            }
                         }
                     });
         }
@@ -1828,7 +1844,7 @@
             }
         }
 
-        int screenId = getIdForScreen(dropTargetLayout);
+        int screenId = getCellLayoutId(dropTargetLayout);
         if (Workspace.EXTRA_EMPTY_SCREEN_IDS.contains(screenId)) {
             commitExtraEmptyScreens();
         }
@@ -1861,12 +1877,9 @@
             return false;
         }
 
-        boolean aboveShortcut = (dropOverView.getTag() instanceof WorkspaceItemInfo
-                && ((WorkspaceItemInfo) dropOverView.getTag()).container
-                != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION);
-        boolean willBecomeShortcut =
-                (info.itemType == ITEM_TYPE_APPLICATION ||
-                        info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT);
+        boolean aboveShortcut = Folder.willAccept(dropOverView.getTag())
+                && ((ItemInfo) dropOverView.getTag()).container != CONTAINER_HOTSEAT_PREDICTION;
+        boolean willBecomeShortcut = Folder.willAcceptItemType(info.itemType);
 
         return (aboveShortcut && willBecomeShortcut);
     }
@@ -1911,14 +1924,14 @@
 
         if (v == null || hasntMoved || !mCreateUserFolderOnDrop) return false;
         mCreateUserFolderOnDrop = false;
-        final int screenId = getIdForScreen(target);
+        final int screenId = getCellLayoutId(target);
 
-        boolean aboveShortcut = (v.getTag() instanceof WorkspaceItemInfo);
-        boolean willBecomeShortcut = (newView.getTag() instanceof WorkspaceItemInfo);
+        boolean aboveShortcut = Folder.willAccept(v.getTag());
+        boolean willBecomeShortcut = Folder.willAccept(newView.getTag());
 
         if (aboveShortcut && willBecomeShortcut) {
-            WorkspaceItemInfo sourceInfo = (WorkspaceItemInfo) newView.getTag();
-            WorkspaceItemInfo destInfo = (WorkspaceItemInfo) v.getTag();
+            ItemInfo sourceInfo = (ItemInfo) newView.getTag();
+            ItemInfo destInfo = (ItemInfo) v.getTag();
             // if the drag started here, we need to remove it from the workspace
             if (!external) {
                 getParentCellLayoutForView(mDragInfo.cell).removeView(mDragInfo.cell);
@@ -2012,7 +2025,7 @@
                         LauncherSettings.Favorites.CONTAINER_HOTSEAT :
                         LauncherSettings.Favorites.CONTAINER_DESKTOP;
                 int screenId = (mTargetCell[0] < 0) ?
-                        mDragInfo.screenId : getIdForScreen(dropTargetLayout);
+                        mDragInfo.screenId : getCellLayoutId(dropTargetLayout);
                 int spanX = mDragInfo != null ? mDragInfo.spanX : 1;
                 int spanY = mDragInfo != null ? mDragInfo.spanY : 1;
                 // First we find the cell nearest to point at which the item is
@@ -2215,8 +2228,7 @@
     private Runnable getWidgetResizeFrameRunnable(DragOptions options,
             LauncherAppWidgetHostView hostView, CellLayout cellLayout) {
         AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
-        if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE
-                && !options.isAccessibleDrag) {
+        if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) {
             return () -> {
                 if (!isPageInTransition()) {
                     AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
@@ -2339,10 +2351,6 @@
         }
     }
 
-    public CellLayout getCurrentDragOverlappingLayout() {
-        return mDragOverlappingLayout;
-    }
-
     void setCurrentDropOverCell(int x, int y) {
         if (x != mDragOverX || y != mDragOverY) {
             mDragOverX = x;
@@ -2377,6 +2385,11 @@
         if (mFolderCreateBg != null) {
             mFolderCreateBg.animateToRest();
         }
+
+        if (mDragOverView instanceof AppPairIcon api) {
+            api.getIconDrawableArea().onTemporaryContainerChange(null);
+            mDragOverView = null;
+        }
     }
 
     private void cleanupAddToFolder() {
@@ -2652,32 +2665,36 @@
             return;
         }
 
-        final View dragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
+        mDragOverView = mDragTargetLayout.getChildAt(mTargetCell[0], mTargetCell[1]);
         ItemInfo info = dragObject.dragInfo;
-        boolean userFolderPending = willCreateUserFolder(info, dragOverView, false);
+        boolean userFolderPending = willCreateUserFolder(info, mDragOverView, false);
         if (mDragMode == DRAG_MODE_NONE && userFolderPending) {
 
             mFolderCreateBg = new PreviewBackground();
             mFolderCreateBg.setup(mLauncher, mLauncher, null,
-                    dragOverView.getMeasuredWidth(), dragOverView.getPaddingTop());
+                    mDragOverView.getMeasuredWidth(), mDragOverView.getPaddingTop());
 
             // The full preview background should appear behind the icon
             mFolderCreateBg.isClipping = false;
 
+            if (mDragOverView instanceof AppPairIcon api) {
+                api.getIconDrawableArea().onTemporaryContainerChange(DISPLAY_FOLDER);
+            }
+
             mFolderCreateBg.animateToAccept(mDragTargetLayout, mTargetCell[0], mTargetCell[1]);
             mDragTargetLayout.clearDragOutlines();
             setDragMode(DRAG_MODE_CREATE_FOLDER);
 
             if (dragObject.stateAnnouncer != null) {
                 dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper
-                        .getDescriptionForDropOver(dragOverView, getContext()));
+                        .getDescriptionForDropOver(mDragOverView, getContext()));
             }
             return;
         }
 
-        boolean willAddToFolder = willAddToExistingUserFolder(info, dragOverView);
+        boolean willAddToFolder = willAddToExistingUserFolder(info, mDragOverView);
         if (willAddToFolder && mDragMode == DRAG_MODE_NONE) {
-            mDragOverFolderIcon = ((FolderIcon) dragOverView);
+            mDragOverFolderIcon = ((FolderIcon) mDragOverView);
             mDragOverFolderIcon.onDragEnter(info);
             if (mDragTargetLayout != null) {
                 mDragTargetLayout.clearDragOutlines();
@@ -2686,7 +2703,7 @@
 
             if (dragObject.stateAnnouncer != null) {
                 dragObject.stateAnnouncer.announce(WorkspaceAccessibilityHelper
-                        .getDescriptionForDropOver(dragOverView, getContext()));
+                        .getDescriptionForDropOver(mDragOverView, getContext()));
             }
             return;
         }
@@ -2772,7 +2789,7 @@
         final int container = mLauncher.isHotseatLayout(cellLayout)
                 ? LauncherSettings.Favorites.CONTAINER_HOTSEAT
                 : LauncherSettings.Favorites.CONTAINER_DESKTOP;
-        final int screenId = getIdForScreen(cellLayout);
+        final int screenId = getCellLayoutId(cellLayout);
         if (!mLauncher.isHotseatLayout(cellLayout)
                 && screenId != getScreenIdForPageIndex(mCurrentPage)
                 && !mLauncher.isInState(SPRING_LOADED)
@@ -2854,36 +2871,9 @@
         } else {
             // This is for other drag/drop cases, like dragging from All Apps
             mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
-            View view;
-
-            switch (info.itemType) {
-                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION:
-                    if (info instanceof WorkspaceItemFactory) {
-                        // Came from all apps -- make a copy
-                        info = ((WorkspaceItemFactory) info).makeWorkspaceItem(mLauncher);
-                        d.dragInfo = info;
-                    }
-                    if (info instanceof WorkspaceItemInfo
-                            && info.container == LauncherSettings.Favorites.CONTAINER_PREDICTION) {
-                        // Came from all apps prediction row -- make a copy
-                        info = new WorkspaceItemInfo((WorkspaceItemInfo) info);
-                        d.dragInfo = info;
-                    }
-                    view = mLauncher.createShortcut(cellLayout, (WorkspaceItemInfo) info);
-                    break;
-                case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                    view = FolderIcon.inflateFolderAndIcon(R.layout.folder_icon, mLauncher, cellLayout,
-                            (FolderInfo) info);
-                    break;
-                case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
-                    view = AppPairIcon.inflateIcon(R.layout.app_pair_icon, mLauncher, cellLayout,
-                            (FolderInfo) info);
-                    break;
-                default:
-                    throw new IllegalStateException("Unknown item type: " + info.itemType);
-            }
+            View view = mLauncher.getItemInflater()
+                    .inflateItem(info, mLauncher.getModelWriter(), cellLayout);
+            d.dragInfo = info = (ItemInfo) view.getTag();
 
             // First we find the cell nearest to point at which the item is
             // dropped, without any consideration to whether there is an item there.
@@ -3008,7 +2998,7 @@
     }
 
     public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, final DragView dragView,
-            final Runnable onCompleteRunnable, int animationType, final View finalView,
+            final Runnable onCompleteRunnable, int animationType, @Nullable final View finalView,
             boolean external) {
         int[] finalPos = new int[2];
         float scaleXY[] = new float[2];
@@ -3334,7 +3324,7 @@
                     }
                 } else if (child instanceof FolderIcon) {
                     FolderInfo folderInfo = (FolderInfo) info;
-                    List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
+                    List<ItemInfo> matches = folderInfo.getContents().stream()
                             .filter(matcher)
                             .collect(Collectors.toList());
                     if (!matches.isEmpty()) {
@@ -3343,6 +3333,11 @@
                             ((FolderIcon) child).getFolder().close(false /* animate */);
                         }
                     }
+                } else if (info instanceof AppPairInfo api) {
+                    // If an app pair's member apps are being removed, delete the whole app pair.
+                    if (api.anyMatch(matcher)) {
+                        mLauncher.removeItem(child, info, true);
+                    }
                 }
             }
         }
@@ -3394,9 +3389,9 @@
                 }
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 FolderInfo fi = (FolderInfo) info;
-                if (fi.contents.stream().anyMatch(matcher)) {
+                if (fi.anyMatch(matcher)) {
                     FolderDotInfo folderDotInfo = new FolderDotInfo();
-                    for (WorkspaceItemInfo si : fi.contents) {
+                    for (ItemInfo si : fi.getContents()) {
                         folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
                     }
                     ((FolderIcon) v).setDotInfo(folderDotInfo);
@@ -3513,14 +3508,15 @@
 
     @Override
     protected String getCurrentPageDescription() {
-        int page = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
-        return getPageDescription(page);
+        int pageIndex = (mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage;
+        return getPageDescription(pageIndex);
     }
 
     /**
      * @param page page index.
      * @return Description of the page at the given page index.
      */
+    @Override
     public String getPageDescription(int page) {
         int nScreens = getChildCount();
         int extraScreenId = mScreenOrder.indexOf(EXTRA_EMPTY_SCREEN_ID);
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index c6c38fc..4768773 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -55,7 +55,6 @@
         int y = presenterPos.cellY;
         if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT
                 || info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
-            Log.d(TAG, "add predicted icon " + child.getTag().toString() + " to home screen");
             int screenId = presenterPos.screenId;
             x = getHotseat().getCellXFromOrder(screenId);
             y = getHotseat().getCellYFromOrder(screenId);
diff --git a/src/com/android/launcher3/accessibility/AccessibleDragListenerAdapter.java b/src/com/android/launcher3/accessibility/AccessibleDragListenerAdapter.java
index 0d7df2b..79b8187 100644
--- a/src/com/android/launcher3/accessibility/AccessibleDragListenerAdapter.java
+++ b/src/com/android/launcher3/accessibility/AccessibleDragListenerAdapter.java
@@ -20,6 +20,8 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.OnHierarchyChangeListener;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.Launcher;
@@ -50,13 +52,13 @@
     @Override
     public void onDragStart(DragObject dragObject, DragOptions options) {
         mViewGroup.setOnHierarchyChangeListener(this);
-        enableAccessibleDrag(true);
+        enableAccessibleDrag(true, dragObject);
     }
 
     @Override
     public void onDragEnd() {
         mViewGroup.setOnHierarchyChangeListener(null);
-        enableAccessibleDrag(false);
+        enableAccessibleDrag(false, null);
         Launcher.getLauncher(mViewGroup.getContext()).getDragController().removeDragListener(this);
     }
 
@@ -75,7 +77,7 @@
         }
     }
 
-    protected void enableAccessibleDrag(boolean enable) {
+    protected void enableAccessibleDrag(boolean enable, @Nullable DragObject dragObject) {
         for (int i = 0; i < mViewGroup.getChildCount(); i++) {
             setEnableForLayout((CellLayout) mViewGroup.getChildAt(i), enable);
         }
diff --git a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
index 19d0421..29862ae 100644
--- a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
@@ -28,7 +28,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -45,6 +45,7 @@
     public enum DragType {
         ICON,
         FOLDER,
+        APP_PAIR,
         WIDGET
     }
 
@@ -103,7 +104,7 @@
                     && item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
         }
         return (item instanceof LauncherAppWidgetInfo)
-                || (item instanceof FolderInfo);
+                || (item instanceof CollectionInfo);
     }
 
     @Override
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 758bffb..814d142 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -5,18 +5,24 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 
+import android.animation.AnimatorSet;
 import android.appwidget.AppWidgetProviderInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Handler;
 import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.ButtonDropTarget;
@@ -32,12 +38,14 @@
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.keyboard.KeyboardDragAndDropView;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.popup.ArrowPopup;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.touch.ItemLongClickListener;
@@ -49,11 +57,13 @@
 import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.views.OptionsPopupView.OptionItem;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 
 public class LauncherAccessibilityDelegate extends BaseAccessibilityDelegate<Launcher> {
 
@@ -70,7 +80,6 @@
     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 SHORTCUTS_AND_NOTIFICATIONS = R.id.action_shortcuts_and_notifications;
 
     public LauncherAccessibilityDelegate(Launcher launcher) {
         super(launcher);
@@ -93,8 +102,6 @@
                 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(SHORTCUTS_AND_NOTIFICATIONS, new LauncherAction(DEEP_SHORTCUTS,
-                R.string.shortcuts_menu_with_notifications_description, KeyEvent.KEYCODE_S));
     }
 
     @Override
@@ -102,8 +109,7 @@
         // If the request came from keyboard, do not add custom shortcuts as that is already
         // exposed as a direct shortcut
         if (ShortcutUtil.supportsShortcuts(item)) {
-            out.add(mActions.get(NotificationListener.getInstanceIfConnected() != null
-                    ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
+            out.add(mActions.get(DEEP_SHORTCUTS));
         }
 
         for (ButtonDropTarget target : mContext.getDropTargetBar().getDropTargets()) {
@@ -131,7 +137,8 @@
     }
 
     private boolean supportAddToWorkSpace(ItemInfo item) {
-        return (item instanceof WorkspaceItemFactory)
+        return ((item instanceof AppInfo)
+                    && (((AppInfo) item).runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0)
                 || ((item instanceof WorkspaceItemInfo)
                     && (((WorkspaceItemInfo) item).runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0)
                 || ((item instanceof PendingAddItemInfo)
@@ -172,7 +179,7 @@
         } else if (action == MOVE) {
             return beginAccessibleDrag(host, item, fromKeyboard);
         } else if (action == ADD_TO_WORKSPACE) {
-            return addToWorkspace(item, true);
+            return addToWorkspace(item, true /*accessibility*/, null /*finishCallback*/);
         } else if (action == MOVE_TO_WORKSPACE) {
             return moveToWorkspace(item);
         } else if (action == RESIZE) {
@@ -188,7 +195,7 @@
                 host.performAccessibilityAction(ACTION_ACCESSIBILITY_FOCUS, null);
             });
             return true;
-        } else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
+        } else if (action == DEEP_SHORTCUTS) {
             BubbleTextView btv = host instanceof BubbleTextView ? (BubbleTextView) host
                     : (host instanceof BubbleTextHolder
                             ? ((BubbleTextHolder) host).getBubbleText() : null);
@@ -312,6 +319,8 @@
         mDragInfo.dragType = DragType.ICON;
         if (info instanceof FolderInfo) {
             mDragInfo.dragType = DragType.FOLDER;
+        } else if (info instanceof AppPairInfo) {
+            mDragInfo.dragType = DragType.APP_PAIR;
         } else if (info instanceof LauncherAppWidgetInfo) {
             mDragInfo.dragType = DragType.WIDGET;
         }
@@ -383,13 +392,19 @@
      * @param item item to be added
      * @param accessibility true if the first item to be added to the workspace
      *     should be focused for accessibility.
+     * @param finishCallback Callback which will be run after this item has been added
+     *                       and the view has been transitioned to the workspace, or on failure.
      *
      * @return true if the item could be successfully added
      */
-    public boolean addToWorkspace(ItemInfo item, boolean accessibility) {
+    public boolean addToWorkspace(ItemInfo item, boolean accessibility,
+            @Nullable Consumer<Boolean> finishCallback) {
         final int[] coordinates = new int[2];
         final int screenId = findSpaceOnWorkspace(item, coordinates);
         if (screenId == -1) {
+            if (finishCallback != null) {
+                finishCallback.accept(false /*success*/);
+            }
             return false;
         }
         mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
@@ -399,35 +414,67 @@
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
 
-                mContext.bindItems(
-                        Collections.singletonList(info),
-                        /* forceAnimateIcons= */ true,
-                        /* focusFirstItemForAccessibility= */ accessibility);
+                bindItem(info, accessibility, finishCallback);
                 announceConfirmation(R.string.item_added_to_workspace);
             } else if (item instanceof PendingAddItemInfo) {
                 PendingAddItemInfo info = (PendingAddItemInfo) item;
+                if (info instanceof PendingAddWidgetInfo widgetInfo
+                        && widgetInfo.bindOptions == null) {
+                    widgetInfo.bindOptions = widgetInfo.getDefaultSizeOptions(mContext);
+                }
                 Workspace<?> workspace = mContext.getWorkspace();
-                workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
-                mContext.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
-                        screenId, coordinates, info.spanX, info.spanY);
+                workspace.post(() -> {
+                    workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+                    workspace.setOnPageTransitionEndCallback(() -> {
+                        mContext.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+                                screenId, coordinates, info.spanX, info.spanY);
+                        if (finishCallback != null) {
+                            finishCallback.accept(/* success= */ true);
+                        }
+                    });
+                });
             } else if (item instanceof WorkspaceItemInfo) {
                 WorkspaceItemInfo info = ((WorkspaceItemInfo) item).clone();
                 mContext.getModelWriter().addItemToDatabase(info,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
-                mContext.bindItems(Collections.singletonList(info), true, accessibility);
-            } else if (item instanceof FolderInfo fi) {
-                mContext.getModelWriter().addItemToDatabase(fi,
+                bindItem(info, accessibility, finishCallback);
+            } else if (item instanceof CollectionInfo ci) {
+                Workspace<?> workspace = mContext.getWorkspace();
+                workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+                mContext.getModelWriter().addItemToDatabase(ci,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0],
                         coordinates[1]);
-                fi.contents.forEach(member -> {
-                    mContext.getModelWriter().addItemToDatabase(member, fi.id, -1, -1, -1);
-                });
-                mContext.bindItems(Collections.singletonList(fi), true, accessibility);
+                ci.getContents().forEach(member ->
+                        mContext.getModelWriter()
+                                .addItemToDatabase(member, ci.id, -1, -1, -1));
+                bindItem(ci, accessibility, finishCallback);
             }
         }));
         return true;
     }
+
+    private void bindItem(ItemInfo item, boolean focusForAccessibility,
+            @Nullable Consumer<Boolean> finishCallback) {
+        View view = mContext.getItemInflater().inflateItem(item, mContext.getModelWriter());
+        if (view == null) {
+            if (finishCallback != null) {
+                finishCallback.accept(false /*success*/);
+            }
+            return;
+        }
+        AnimatorSet anim = new AnimatorSet();
+        anim.addListener(forEndCallback((success) -> {
+            if (focusForAccessibility) {
+                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+            }
+            if (finishCallback != null) {
+                finishCallback.accept(success);
+            }
+        }));
+        mContext.bindInflatedItems(Collections.singletonList(Pair.create(item, view)), anim);
+    }
+
     /**
      * Functionality to move the item {@link ItemInfo} to the workspace
      * @param item item to be moved
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index fb847ec..d115f9f 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -19,7 +19,6 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 
-import android.view.KeyEvent;
 import android.view.View;
 
 import com.android.launcher3.AbstractFloatingView;
@@ -28,7 +27,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.notification.NotificationMainView;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 
 import java.util.Collections;
@@ -40,22 +38,14 @@
  */
 public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDelegate {
 
-    private static final int DISMISS_NOTIFICATION = R.id.action_dismiss_notification;
-
     public ShortcutMenuAccessibilityDelegate(Launcher launcher) {
         super(launcher);
-        mActions.put(DISMISS_NOTIFICATION, new LauncherAction(DISMISS_NOTIFICATION,
-                R.string.action_dismiss_notification, KeyEvent.KEYCODE_X));
     }
 
     @Override
     protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
         if ((host.getParent() instanceof DeepShortcutView)) {
             out.add(mActions.get(ADD_TO_WORKSPACE));
-        } else if (host instanceof NotificationMainView) {
-            if (((NotificationMainView) host).canChildBeDismissed()) {
-                out.add(mActions.get(DISMISS_NOTIFICATION));
-            }
         }
     }
 
@@ -80,13 +70,6 @@
                 announceConfirmation(R.string.item_added_to_workspace);
             }));
             return true;
-        } else if (action == DISMISS_NOTIFICATION) {
-            if (!(host instanceof NotificationMainView)) {
-                return false;
-            }
-            ((NotificationMainView) host).onChildDismissed();
-            announceConfirmation(R.string.notification_dismissed);
-            return true;
         }
         return false;
     }
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index a8624dd..84d6a6f 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.BaseAccessibilityDelegate.DragType;
+import com.android.launcher3.folder.Folder;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -117,7 +118,7 @@
             return mContext.getString(R.string.item_moved);
         } else {
             ItemInfo info = (ItemInfo) child.getTag();
-            if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
+            if (Folder.willAccept(info)) {
                 return mContext.getString(R.string.folder_created);
 
             } else if (info instanceof FolderInfo) {
@@ -148,8 +149,8 @@
             if (TextUtils.isEmpty(info.title)) {
                 // Find the first item in the folder.
                 FolderInfo folder = (FolderInfo) info;
-                WorkspaceItemInfo firstItem = null;
-                for (WorkspaceItemInfo shortcut : folder.contents) {
+                ItemInfo firstItem = null;
+                for (ItemInfo shortcut : folder.getContents()) {
                     if (firstItem == null || firstItem.rank > shortcut.rank) {
                         firstItem = shortcut;
                     }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 7f1d216..8026d4a 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.Flags.enableExpandingPauseWorkButton;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
 import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY;
@@ -70,7 +71,6 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
@@ -80,11 +80,13 @@
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
+import com.android.launcher3.keyboard.ViewGroupFocusHelper;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.recyclerview.AllAppsRecyclerViewPool;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
@@ -96,6 +98,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
@@ -156,6 +159,7 @@
             };
     private final Paint mNavBarScrimPaint;
     private final int mHeaderProtectionColor;
+    private final int mPrivateSpaceBottomExtraSpace;
     private final Path mTmpPath = new Path();
     private final RectF mTmpRectF = new RectF();
     protected AllAppsPagedView mViewPager;
@@ -189,8 +193,6 @@
     private int mTabsProtectionAlpha;
     @Nullable private AllAppsTransitionController mAllAppsTransitionController;
 
-    private PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
-
     public ActivityAllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -219,6 +221,8 @@
                 this,
                 mActivityContext.getStatsLogManager(),
                 UserCache.INSTANCE.get(mActivityContext));
+        mPrivateSpaceBottomExtraSpace = context.getResources().getDimensionPixelSize(
+                R.dimen.ps_extra_bottom_padding);
         mAH = Arrays.asList(null, null, null);
         mNavBarScrimPaint = new Paint();
         mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
@@ -258,10 +262,6 @@
      */
     protected void initContent() {
         mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
-        if (Flags.enablePrivateSpace()) {
-            mPrivateSpaceHeaderViewController =
-                    new PrivateSpaceHeaderViewController(mPrivateProfileManager);
-        }
 
         mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
                 new AlphabeticalAppsList<>(mActivityContext,
@@ -395,7 +395,7 @@
         mAllAppsTransitionController = allAppsTransitionController;
     }
 
-    private void animateToSearchState(boolean goingToSearch, long durationMs) {
+    void animateToSearchState(boolean goingToSearch, long durationMs) {
         if (!mSearchTransitionController.isRunning() && goingToSearch == isSearching()) {
             return;
         }
@@ -496,9 +496,9 @@
     }
 
     /**
-     * Exits search and returns to A-Z apps list. Scroll to the bottom.
+     * Exits search and returns to A-Z apps list. Scroll to the private space header.
      */
-    public void resetAndScrollToBottom() {
+    public void resetAndScrollToPrivateSpaceHeader() {
         if (mTouchHandler != null) {
             mTouchHandler.endFastScrolling();
         }
@@ -515,7 +515,13 @@
             // Switch to the main tab
             switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
             // Scroll to bottom
-            getActiveRecyclerView().scrollToBottomWithMotion();
+            if (mPrivateProfileManager != null) {
+                mPrivateProfileManager.scrollForHeaderToBeVisibleInContainer(
+                        getActiveAppsRecyclerView(),
+                        getPersonalAppList().getAdapterItems(),
+                        mPrivateProfileManager.getPsHeaderHeight(),
+                        mActivityContext.getDeviceProfile().allAppsCellHeightPx);
+            }
         });
     }
 
@@ -771,7 +777,7 @@
     protected void updateHeaderScroll(int scrolledOffset) {
         float prog1 = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
         int headerColor = getHeaderColor(prog1);
-        int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0
+        int tabsAlpha = mHeader.getPeripheralProtectionHeight(/* expectedHeight */ false) == 0 ? 0
                 : (int) (Utilities.boundToRange(
                         (scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f)
                         * 255);
@@ -903,7 +909,7 @@
 
     protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList) {
         return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
-                mMainAdapterProvider, mPrivateSpaceHeaderViewController);
+                mMainAdapterProvider);
     }
 
     // TODO(b/216683257): Remove when Taskbar All Apps supports search.
@@ -980,6 +986,11 @@
         return mWorkManager;
     }
 
+    /** Returns whether Private Profile has been setup. */
+    public boolean hasPrivateProfile() {
+        return mHasPrivateApps;
+    }
+
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
         for (AdapterHolder holder : mAH) {
@@ -1151,13 +1162,16 @@
         applyAdapterSideAndBottomPaddings(grid);
 
         MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
-        mlp.leftMargin = insets.left;
-        mlp.rightMargin = insets.right;
+        // Ignore left/right insets on tablet because we are already centered in-screen.
+        if (grid.isTablet) {
+            mlp.leftMargin = mlp.rightMargin = 0;
+        } else {
+            mlp.leftMargin = insets.left;
+            mlp.rightMargin = insets.right;
+        }
         setLayoutParams(mlp);
 
-        if (grid.isVerticalBarLayout() && !FeatureFlags.enableResponsiveWorkspace()) {
-            setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
-        } else {
+        if (!grid.isVerticalBarLayout() || FeatureFlags.enableResponsiveWorkspace()) {
             int topPadding = grid.allAppsPadding.top;
             if (isSearchBarFloating() && !grid.isTablet) {
                 topPadding += getResources().getDimensionPixelSize(
@@ -1314,6 +1328,10 @@
                 : mViewPager == null ? AdapterHolder.MAIN : mViewPager.getNextPage();
     }
 
+    public PrivateProfileManager getPrivateProfileManager() {
+        return mPrivateProfileManager;
+    }
+
     /**
      * Adds an update listener to animator that adds springs to the animation.
      */
@@ -1353,12 +1371,25 @@
         invalidateHeader();
     }
 
+    /**
+     * Set {@link Animator.AnimatorListener} on {@link mAllAppsTransitionController} to observe
+     * animation of backing out of all apps search view to all apps view.
+     */
+    public void setAllAppsSearchBackAnimatorListener(Animator.AnimatorListener listener) {
+        Preconditions.assertNotNull(mAllAppsTransitionController);
+        if (mAllAppsTransitionController == null) {
+            return;
+        }
+        mAllAppsTransitionController.setAllAppsSearchBackAnimationListener(listener);
+    }
+
     public void setScrimView(ScrimView scrimView) {
         mScrimView = scrimView;
     }
 
     @Override
-    public void drawOnScrimWithScale(Canvas canvas, float scale) {
+    public void drawOnScrimWithScaleAndBottomOffset(
+            Canvas canvas, float scale, @Px int bottomOffsetPx) {
         final View panel = mBottomSheetBackground;
         final boolean hasBottomSheet = panel.getVisibility() == VISIBLE;
         final float translationY = ((View) panel.getParent()).getTranslationY();
@@ -1370,6 +1401,7 @@
         final float topWithScale = topNoScale + verticalScaleOffset;
         final float leftWithScale = panel.getLeft() + horizontalScaleOffset;
         final float rightWithScale = panel.getRight() - horizontalScaleOffset;
+        final float bottomWithOffset = panel.getBottom() + bottomOffsetPx;
         // Draw full background panel for tablets.
         if (hasBottomSheet) {
             mHeaderPaint.setColor(mBottomSheetBackgroundColor);
@@ -1379,7 +1411,7 @@
                     leftWithScale,
                     topWithScale,
                     rightWithScale,
-                    panel.getBottom());
+                    bottomWithOffset);
             mTmpPath.reset();
             mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
             canvas.drawPath(mTmpPath, mHeaderPaint);
@@ -1421,7 +1453,7 @@
         }
 
         // If tab exist (such as work profile), extend header with tab height
-        final int tabsHeight = headerView.getPeripheralProtectionHeight();
+        final int tabsHeight = headerView.getPeripheralProtectionHeight(/* expectedHeight */ false);
         if (mTabsProtectionAlpha > 0 && tabsHeight != 0) {
             if (DEBUG_HEADER_PROTECTION) {
                 mHeaderPaint.setColor(Color.BLUE);
@@ -1451,6 +1483,18 @@
     }
 
     /**
+     * The height of the header protection as if the user scrolled down the app list.
+     */
+    float getHeaderProtectionHeight() {
+        float headerBottom = getHeaderBottom() - getTranslationY();
+        if (mUsingTabs) {
+            return headerBottom + mHeader.getPeripheralProtectionHeight(/* expectedHeight */ true);
+        } else {
+            return headerBottom;
+        }
+    }
+
+    /**
      * redraws header protection
      */
     public void invalidateHeader() {
@@ -1471,6 +1515,10 @@
         return bottom + mHeader.getTop();
     }
 
+    boolean isUsingTabs() {
+        return mUsingTabs;
+    }
+
     /**
      * Returns a view that denotes the visible part of all apps container view.
      */
@@ -1522,7 +1570,11 @@
             // No animations will occur when changes occur to the items in this RecyclerView.
             mRecyclerView.setItemAnimator(null);
             onInitializeRecyclerView(mRecyclerView);
-            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
+            // Use ViewGroupFocusHelper for SearchRecyclerView to draw focus outline for the
+            // buttons in the view (e.g. query builder button and setting button)
+            FocusedItemDecorator focusedItemDecorator = isSearch() ? new FocusedItemDecorator(
+                    new ViewGroupFocusHelper(mRecyclerView)) : new FocusedItemDecorator(
+                    mRecyclerView);
             mRecyclerView.addItemDecoration(focusedItemDecorator);
             mOnFocusChangeListener = focusedItemDecorator.getFocusListener();
             mAdapter.setIconFocusListener(mOnFocusChangeListener);
@@ -1534,6 +1586,14 @@
                 int bottomOffset = 0;
                 if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
                     bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
+                } else if (isMain() && mPrivateProfileManager != null) {
+                    Optional<AdapterItem> privateSpaceHeaderItem = mAppsList.getAdapterItems()
+                            .stream()
+                            .filter(item -> item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER)
+                            .findFirst();
+                    if (privateSpaceHeaderItem.isPresent()) {
+                        bottomOffset = mPrivateSpaceBottomExtraSpace;
+                    }
                 }
                 if (isSearchBarFloating()) {
                     bottomOffset += mSearchContainer.getHeight();
@@ -1550,5 +1610,9 @@
         private boolean isSearch() {
             return mType == SEARCH;
         }
+
+        private boolean isMain() {
+            return mType == MAIN;
+        }
     }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 7067fa2..911612f 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -71,7 +71,7 @@
 
         @Override
         protected int getVerticalSnapPreference() {
-            return SNAP_TO_START;
+            return SNAP_TO_ANY;
         }
 
         @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 5f002b5..df383bf 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -73,9 +73,8 @@
 
 
     public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
-            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider,
-            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
-        super(activityContext, inflater, apps, adapterProvider, privateSpaceHeaderViewController);
+            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider) {
+        super(activityContext, inflater, apps, adapterProvider);
         mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
         mGridLayoutMgr.setSpanSizeLookup(new GridSpanSizer());
         setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 36a44cc..ba34f59 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -180,7 +180,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
     @Override
-    public String scrollToPositionAtProgress(float touchFraction) {
+    public CharSequence scrollToPositionAtProgress(float touchFraction) {
         int rowCount = mApps.getNumAppRows();
         if (rowCount == 0) {
             return "";
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 051cf50..9623709 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -40,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -93,11 +94,14 @@
      * Sets the current set of apps and sets mapping for {@link PackageUserKey} to Uid for
      * the current set of apps.
      *
-     * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because this
-     * method is too late to preinflate all apps, as user will open all apps in the same frame.
+     * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because
+     * this method is too late to preinflate all apps, as user will open all apps in the frame
+     *
+     * <p>Param: apps are required to be sorted using the comparator COMPONENT_KEY_COMPARATOR
+     * in order to enable binary search on the mApps store
      */
     public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map,
-            boolean shouldPreinflate)  {
+            boolean shouldPreinflate) {
         mApps = apps == null ? EMPTY_ARRAY : apps;
         mModelFlags = flags;
         notifyUpdate();
@@ -135,12 +139,22 @@
     /**
      * Returns {@link AppInfo} if any apps matches with provided {@link ComponentKey}, otherwise
      * null.
+     *
+     * Uses {@link AppInfo#COMPONENT_KEY_COMPARATOR} as a default comparator.
      */
     @Nullable
     public AppInfo getApp(ComponentKey key) {
+        return getApp(key, COMPONENT_KEY_COMPARATOR);
+    }
+
+    /**
+     * Generic version of {@link #getApp(ComponentKey)} that allows comparator to be specified.
+     */
+    @Nullable
+    public AppInfo getApp(ComponentKey key, Comparator<AppInfo> comparator) {
         mTempInfo.componentName = key.componentName;
         mTempInfo.user = key.user;
-        int index = Arrays.binarySearch(mApps, mTempInfo, COMPONENT_KEY_COMPARATOR);
+        int index = Arrays.binarySearch(mApps, mTempInfo, comparator);
         return index < 0 ? null : mApps[index];
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 03ac9df..1b0ad04 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -24,6 +24,9 @@
 import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER;
+import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
+import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
@@ -38,8 +41,6 @@
 import android.util.FloatProperty;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.animation.Interpolator;
 
 import androidx.annotation.FloatRange;
@@ -167,6 +168,8 @@
     private final AnimatedFloat mAllAppScale = new AnimatedFloat(this::onScaleProgressChanged);
     private final int mNavScrimFlag;
 
+    @Nullable private Animator.AnimatorListener mAllAppsSearchBackAnimationListener;
+
     private boolean mIsVerticalLayout;
 
     // Animation in this class is controlled by a single variable {@link mProgress}.
@@ -280,8 +283,7 @@
             return;
         }
 
-        float deceleratedProgress =
-                Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(backProgress);
+        float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(backProgress);
         float scaleProgress = ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE
                 + (1 - ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE)
                 * (1 - deceleratedProgress);
@@ -292,12 +294,11 @@
     private void onScaleProgressChanged() {
         final float scaleProgress = mAllAppScale.value;
         SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
-        mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+        if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+            mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+        }
 
         AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
-        if (rv != null && rv.getScrollbar() != null) {
-            rv.getScrollbar().setVisibility(scaleProgress < 1f ? View.INVISIBLE : View.VISIBLE);
-        }
 
         // Disable view clipping from all apps' RecyclerView up to all apps view during scale
         // animation, and vice versa. The goal is to display extra roll(s) app icons (rendered in
@@ -306,18 +307,34 @@
         if (hasScaleEffect != mHasScaleEffect) {
             mHasScaleEffect = hasScaleEffect;
             if (mHasScaleEffect) {
-                setClipChildrenOnViewTree(rv, mLauncher.getAppsView(), false);
+                modifyAttributesOnViewTree(rv, mLauncher.getAppsView(),
+                        CLIP_CHILDREN_FALSE_MODIFIER);
             } else {
-                restoreClipChildrenOnViewTree(rv, mLauncher.getAppsView());
+                restoreAttributesOnViewTree(rv, mLauncher.getAppsView(),
+                        CLIP_CHILDREN_FALSE_MODIFIER);
             }
         }
     }
 
-    /** Animate all apps view to 1f scale. */
+    /** Set {@link Animator.AnimatorListener} for scaling all apps scale to 1 animation. */
+    public void setAllAppsSearchBackAnimationListener(Animator.AnimatorListener listener) {
+        mAllAppsSearchBackAnimationListener = listener;
+    }
+
+    /**
+     * Animate all apps view to 1f scale. This is called when backing (exiting) from all apps
+     * search view to all apps view.
+     */
     public void animateAllAppsToNoScale() {
-        mAllAppScale.animateToValue(1f)
-                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
-                .start();
+        if (mAllAppScale.isAnimating()) {
+            return;
+        }
+        Animator animator = mAllAppScale.animateToValue(1f)
+                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS);
+        if (mAllAppsSearchBackAnimationListener != null) {
+            animator.addListener(mAllAppsSearchBackAnimationListener);
+        }
+        animator.start();
     }
 
     /**
@@ -342,7 +359,7 @@
             });
         }
 
-        if(FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.userControlled
+        if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.isUserControlled()
                 && Utilities.ATLEAST_S) {
             if (toState == ALL_APPS) {
                 builder.addOnFrameListener(
@@ -367,7 +384,7 @@
 
         // need to decide depending on the release velocity
         Interpolator verticalProgressInterpolator = config.getInterpolator(ANIM_VERTICAL_PROGRESS,
-                config.userControlled ? LINEAR : DECELERATE_1_7);
+                config.isUserControlled() ? LINEAR : DECELERATE_1_7);
         Animator anim = createSpringAnimation(mProgress, targetProgress);
         anim.setInterpolator(verticalProgressInterpolator);
         builder.add(anim);
@@ -423,79 +440,6 @@
     }
 
     /**
-     * Recursively call {@link ViewGroup#setClipChildren(boolean)} from {@link View} to ts parent
-     * (direct or indirect) inclusive. This method will also save the old clipChildren value on each
-     * view with {@link View#setTag(int, Object)}, which can be restored in
-     * {@link #restoreClipChildrenOnViewTree(View, ViewParent)}.
-     *
-     * Note that if parent is null or not a parent of the view, this method will be applied all the
-     * way to root view.
-     *
-     * @param v child view
-     * @param parent direct or indirect parent of child view
-     * @param clipChildren whether we should clip children
-     */
-    private static void setClipChildrenOnViewTree(
-            @Nullable View v,
-            @Nullable ViewParent parent,
-            boolean clipChildren) {
-        if (v == null) {
-            return;
-        }
-
-        if (v instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) v;
-            boolean oldClipChildren = viewGroup.getClipChildren();
-            if (oldClipChildren != clipChildren) {
-                v.setTag(R.id.saved_clip_children_tag_id, oldClipChildren);
-                viewGroup.setClipChildren(clipChildren);
-            }
-        }
-
-        if (v == parent) {
-            return;
-        }
-
-        if (v.getParent() instanceof View) {
-            setClipChildrenOnViewTree((View) v.getParent(), parent, clipChildren);
-        }
-    }
-
-    /**
-     * Recursively call {@link ViewGroup#setClipChildren(boolean)} to restore clip children value
-     * set in {@link #setClipChildrenOnViewTree(View, ViewParent, boolean)} on view to its parent
-     * (direct or indirect) inclusive.
-     *
-     * Note that if parent is null or not a parent of the view, this method will be applied all the
-     * way to root view.
-     *
-     * @param v child view
-     * @param parent direct or indirect parent of child view
-     */
-    private static void restoreClipChildrenOnViewTree(
-            @Nullable View v, @Nullable ViewParent parent) {
-        if (v == null) {
-            return;
-        }
-        if (v instanceof ViewGroup) {
-            ViewGroup viewGroup = (ViewGroup) v;
-            Object viewTag = viewGroup.getTag(R.id.saved_clip_children_tag_id);
-            if (viewTag instanceof Boolean) {
-                viewGroup.setClipChildren((boolean) viewTag);
-                viewGroup.setTag(R.id.saved_clip_children_tag_id, null);
-            }
-        }
-
-        if (v == parent) {
-            return;
-        }
-
-        if (v.getParent() instanceof View) {
-            restoreClipChildrenOnViewTree((View) v.getParent(), parent);
-        }
-    }
-
-    /**
      * Updates the total scroll range but does not update the UI.
      */
     public void setShiftRange(float shiftRange) {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 1782791..a810331 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -18,13 +18,20 @@
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT;
 
 import android.content.Context;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.DiffUtil;
 
 import com.android.launcher3.Flags;
+import com.android.launcher3.R;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -34,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Objects;
 import java.util.TreeMap;
 import java.util.function.Predicate;
@@ -60,11 +68,11 @@
      */
     public static class FastScrollSectionInfo {
         // The section name
-        public final String sectionName;
+        public final CharSequence sectionName;
         // The item position
         public final int position;
 
-        public FastScrollSectionInfo(String sectionName, int position) {
+        public FastScrollSectionInfo(CharSequence sectionName, int position) {
             this.sectionName = sectionName;
             this.position = position;
         }
@@ -88,6 +96,7 @@
 
     // The of ordered component names as a result of a search query
     private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
+    private final SpannableString mPrivateProfileAppScrollerBadge;
     private BaseAllAppsAdapter<T> mAdapter;
     private AppInfoComparator mAppNameComparator;
     private int mNumAppsPerRowAllApps;
@@ -105,6 +114,10 @@
         if (mAllAppsStore != null) {
             mAllAppsStore.addUpdateListener(this);
         }
+        mPrivateProfileAppScrollerBadge = new SpannableString(" ");
+        mPrivateProfileAppScrollerBadge.setSpan(new ImageSpan(context,
+                        R.drawable.ic_private_profile_app_scroller_badge, ImageSpan.ALIGN_CENTER),
+                0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     }
 
     /** Set the number of apps per row when device profile changes. */
@@ -201,7 +214,10 @@
      */
     @Override
     public void onAppsUpdated() {
-        if (mAllAppsStore == null) {
+        // Don't update apps when the private profile animations are running, otherwise the motion
+        // is canceled.
+        if (mAllAppsStore == null || (mPrivateProviderManager != null &&
+                mPrivateProviderManager.getAnimationRunning())) {
             return;
         }
         // Sort the list of apps
@@ -268,10 +284,16 @@
                 addApps = mWorkProviderManager.shouldShowWorkApps();
             }
             if (addApps) {
-                addAppsWithSections(mApps, position);
+                if (/* education card was added */ position == 1) {
+                    // Add work educard section with "info icon" at 0th position.
+                    mFastScrollerSections.add(new FastScrollSectionInfo(
+                            mActivityContext.getResources().getString(
+                                    R.string.work_profile_edu_section), 0));
+                }
+                position = addAppsWithSections(mApps, position);
             }
             if (Flags.enablePrivateSpace()) {
-                addPrivateSpaceItems(position);
+                position = addPrivateSpaceItems(position);
             }
         }
         mAccessibilityResultsCount = (int) mAdapterItems.stream()
@@ -286,7 +308,8 @@
             for (AdapterItem item : mAdapterItems) {
                 item.rowIndex = 0;
                 if (BaseAllAppsAdapter.isDividerViewType(item.viewType)
-                        || BaseAllAppsAdapter.isPrivateSpaceHeaderView(item.viewType)) {
+                        || BaseAllAppsAdapter.isPrivateSpaceHeaderView(item.viewType)
+                        || BaseAllAppsAdapter.isPrivateSpaceSysAppsDividerView(item.viewType)) {
                     numAppsInSection = 0;
                 } else if (BaseAllAppsAdapter.isIconViewType(item.viewType)) {
                     if (numAppsInSection % mNumAppsPerRowAllApps == 0) {
@@ -308,12 +331,12 @@
         }
     }
 
-    void addPrivateSpaceItems(int position) {
+    int addPrivateSpaceItems(int position) {
         if (mPrivateProviderManager != null
                 && !mPrivateProviderManager.isPrivateSpaceHidden()
                 && !mPrivateApps.isEmpty()) {
             // Always add PS Header if Space is present and visible.
-            position += mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+            position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
             int privateSpaceState = mPrivateProviderManager.getCurrentState();
             switch (privateSpaceState) {
                 case PrivateProfileManager.STATE_DISABLED:
@@ -321,43 +344,66 @@
                     break;
                 case PrivateProfileManager.STATE_ENABLED:
                     // Add PS Apps only in Enabled State.
-                    addAppsWithSections(mPrivateApps, position);
-                    if (mActivityContext.getAppsView() != null) {
-                        mActivityContext.getAppsView().getActiveRecyclerView()
-                                .scrollToBottomWithMotion();
-                    }
+                    position = addPrivateSpaceApps(position);
                     break;
             }
         }
+        return position;
     }
 
-    private void addAppsWithSections(List<AppInfo> appList, int startPosition) {
+    private int addPrivateSpaceApps(int position) {
+        // Add Install Apps Button first.
+        if (Flags.privateSpaceAppInstallerButton()) {
+            mPrivateProviderManager.addPrivateSpaceInstallAppButton(mAdapterItems);
+            position++;
+        }
+
+        // Split of private space apps into user-installed and system apps.
+        Map<Boolean, List<AppInfo>> split = mPrivateApps.stream()
+                .collect(Collectors.partitioningBy(mPrivateProviderManager
+                                .splitIntoUserInstalledAndSystemApps(mActivityContext)));
+
+        // TODO(b/329688630): switch to the pulled LayoutStaticSnapshot atom
+        mActivityContext
+                .getStatsLogManager()
+                .logger()
+                .withCardinality(split.get(true).size())
+                .log(LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT);
+
+        mActivityContext
+                .getStatsLogManager()
+                .logger()
+                .withCardinality(split.get(false).size())
+                .log(LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT);
+
+        // Add user installed apps
+        position = addAppsWithSections(split.get(true), position);
+        // Add system apps separator.
+        if (Flags.privateSpaceSysAppsSeparation()) {
+            position = mPrivateProviderManager.addSystemAppsDivider(mAdapterItems);
+        }
+        // Add system apps.
+        position = addAppsWithSections(split.get(false), position);
+
+        return position;
+    }
+
+    private int addAppsWithSections(List<AppInfo> appList, int startPosition) {
         String lastSectionName = null;
         boolean hasPrivateApps = false;
+        int position = startPosition;
         if (mPrivateProviderManager != null) {
             hasPrivateApps = appList.stream().
                     allMatch(mPrivateProviderManager.getItemInfoMatcher());
         }
-        int privateAppCount = 0;
-        int numberOfColumns = mActivityContext.getDeviceProfile().numShownAllAppsColumns;
-        int numberOfAppRows = (int) Math.ceil((double) appList.size() / numberOfColumns);
-        for (AppInfo info : appList) {
+        for (int i = 0; i < appList.size(); i++) {
+            AppInfo info = appList.get(i);
             // Apply decorator to private apps.
             if (hasPrivateApps) {
-                int roundRegion = ROUND_NOTHING;
-                if ((privateAppCount / numberOfColumns) == numberOfAppRows - 1) {
-                    if ((privateAppCount % numberOfColumns) == 0) {
-                        // App is the first column
-                        roundRegion = ROUND_BOTTOM_LEFT;
-                    } else if ((privateAppCount % numberOfColumns) == numberOfColumns-1) {
-                        roundRegion = ROUND_BOTTOM_RIGHT;
-                    }
-                }
                 mAdapterItems.add(AdapterItem.asAppWithDecorationInfo(info,
                         new SectionDecorationInfo(mActivityContext.getApplicationContext(),
-                                roundRegion,
+                                getRoundRegions(i, appList.size()),
                                 true /* decorateTogether */)));
-                privateAppCount += 1;
             } else {
                 mAdapterItems.add(AdapterItem.asApp(info));
             }
@@ -366,10 +412,53 @@
             // Create a new section if the section names do not match
             if (!sectionName.equals(lastSectionName)) {
                 lastSectionName = sectionName;
-                mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, startPosition));
+                mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
+                        mPrivateProfileAppScrollerBadge : sectionName, position));
             }
-            startPosition++;
+            position++;
         }
+        return position;
+    }
+
+    /**
+     * Determines the corner regions that should be rounded for a specific app icon based on its
+     * position in a grid. Apps that should only be cared about rounding are the apps in the last
+     * row. In the last row on the first column, the app should only be rounded on the bottom left.
+     * Apps in the middle would not be rounded and the last app on the last row will ALWAYS have a
+     * {@link SectionDecorationInfo#ROUND_BOTTOM_RIGHT}.
+     *
+     * @param appIndex The index of the app icon within the app list.
+     * @param appListSize The total number of apps within the app list.
+     * @return  An integer representing the corner regions to be rounded, using bitwise flags:
+     *          - {@link SectionDecorationInfo#ROUND_NOTHING}: No corners should be rounded.
+     *          - {@link SectionDecorationInfo#ROUND_TOP_LEFT}: Round the top-left corner.
+     *          - {@link SectionDecorationInfo#ROUND_TOP_RIGHT}: Round the top-right corner.
+     *          - {@link SectionDecorationInfo#ROUND_BOTTOM_LEFT}: Round the bottom-left corner.
+     *          - {@link SectionDecorationInfo#ROUND_BOTTOM_RIGHT}: Round the bottom-right corner.
+     */
+    @VisibleForTesting
+    int getRoundRegions(int appIndex, int appListSize) {
+        int numberOfAppRows = (int) Math.ceil((double) appListSize / mNumAppsPerRowAllApps);
+        int roundRegion = ROUND_NOTHING;
+        // App is in the last row.
+        if ((appIndex / mNumAppsPerRowAllApps) == numberOfAppRows - 1) {
+            if ((appIndex % mNumAppsPerRowAllApps) == 0) {
+                // App is the first column.
+                roundRegion = ROUND_BOTTOM_LEFT;
+            } else if ((appIndex % mNumAppsPerRowAllApps) == mNumAppsPerRowAllApps-1) {
+                // App is in the last column.
+                roundRegion = ROUND_BOTTOM_RIGHT;
+            }
+            // Ensure the last private app is rounded on the bottom right.
+            if (appIndex == appListSize - 1) {
+                roundRegion |= ROUND_BOTTOM_RIGHT;
+            }
+        }
+        return roundRegion;
+    }
+
+    public PrivateProfileManager getPrivateProfileManager() {
+        return mPrivateProviderManager;
     }
 
     private static class MyDiffCallback extends DiffUtil.Callback {
diff --git a/src/com/android/launcher3/allapps/AppInfoComparator.java b/src/com/android/launcher3/allapps/AppInfoComparator.java
index 311a40e..bbf8e5a 100644
--- a/src/com/android/launcher3/allapps/AppInfoComparator.java
+++ b/src/com/android/launcher3/allapps/AppInfoComparator.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.os.Process;
 import android.os.UserHandle;
+import android.text.TextUtils;
 
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.pm.UserCache;
@@ -43,9 +44,7 @@
     @Override
     public int compare(AppInfo a, AppInfo b) {
         // Order by the title in the current locale
-        int result = mLabelComparator.compare(
-                a.title == null ? "" : a.title.toString(),
-                b.title == null ? "" : b.title.toString());
+        int result = mLabelComparator.compare(getSortingTitle(a), getSortingTitle(b));
         if (result != 0) {
             return result;
         }
@@ -64,4 +63,14 @@
             return aUserSerial.compareTo(bUserSerial);
         }
     }
+
+    private String getSortingTitle(AppInfo info) {
+        if (!TextUtils.isEmpty(info.appTitle)) {
+            return info.appTitle.toString();
+        }
+        if (info.title != null) {
+            return info.title.toString();
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 5eeb259..a21d7be 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -15,11 +15,15 @@
  */
 package com.android.launcher3.allapps;
 
+import static android.view.View.GONE;
+
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_LEFT;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_RIGHT;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
 
 import android.content.Context;
 import android.view.LayoutInflater;
@@ -35,10 +39,12 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.views.ActivityContext;
 
 /**
@@ -61,7 +67,8 @@
     public static final int VIEW_TYPE_WORK_EDU_CARD = 1 << 4;
     public static final int VIEW_TYPE_WORK_DISABLED_CARD = 1 << 5;
     public static final int VIEW_TYPE_PRIVATE_SPACE_HEADER = 1 << 6;
-    public static final int NEXT_ID = 7;
+    public static final int VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER = 1 << 7;
+    public static final int NEXT_ID = 8;
 
     // Common view type masks
     public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
@@ -69,6 +76,8 @@
 
     public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER =
             VIEW_TYPE_PRIVATE_SPACE_HEADER;
+    public static final int VIEW_TYPE_MASK_PRIVATE_SPACE_SYS_APPS_DIVIDER =
+            VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
 
     protected final SearchAdapterProvider<?> mAdapterProvider;
 
@@ -163,16 +172,9 @@
     protected final OnClickListener mOnIconClickListener;
     protected final OnLongClickListener mOnIconLongClickListener;
     protected OnFocusChangeListener mIconFocusListener;
-    private final PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
 
     public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
             AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
-        this(activityContext, inflater, apps, adapterProvider, null);
-    }
-
-    public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
-            AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider,
-            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
         mActivityContext = activityContext;
         mApps = apps;
         mLayoutInflater = inflater;
@@ -181,7 +183,6 @@
         mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
 
         mAdapterProvider = adapterProvider;
-        mPrivateSpaceHeaderViewController = privateSpaceHeaderViewController;
     }
 
     /** Checks if the passed viewType represents all apps divider. */
@@ -199,6 +200,11 @@
         return isViewType(viewType, VIEW_TYPE_MASK_PRIVATE_SPACE_HEADER);
     }
 
+    /** Checks if the passed viewType represents private space system apps divider. */
+    public static boolean isPrivateSpaceSysAppsDividerView(int viewType) {
+        return isViewType(viewType, VIEW_TYPE_MASK_PRIVATE_SPACE_SYS_APPS_DIVIDER);
+    }
+
     public void setIconFocusListener(OnFocusChangeListener focusListener) {
         mIconFocusListener = focusListener;
     }
@@ -212,8 +218,10 @@
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case VIEW_TYPE_ICON:
-                int layout = !FeatureFlags.enableTwolineAllapps() ? R.layout.all_apps_icon
-                                : R.layout.all_apps_icon_twoline;
+                int layout = (Flags.enableTwolineToggle()
+                        && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(
+                                mActivityContext.getApplicationContext()))
+                        ? R.layout.all_apps_icon_twoline : R.layout.all_apps_icon;
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
                         layout, parent, false);
                 icon.setLongPressTimeoutFactor(1f);
@@ -227,9 +235,9 @@
             case VIEW_TYPE_EMPTY_SEARCH:
                 return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
                         parent, false));
-            case VIEW_TYPE_ALL_APPS_DIVIDER:
+            case VIEW_TYPE_ALL_APPS_DIVIDER, VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER:
                 return new ViewHolder(mLayoutInflater.inflate(
-                        R.layout.all_apps_divider, parent, false));
+                        R.layout.private_space_divider, parent, false));
             case VIEW_TYPE_WORK_EDU_CARD:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.work_apps_edu, parent, false));
@@ -249,6 +257,7 @@
 
     @Override
     public void onBindViewHolder(ViewHolder holder, int position) {
+        holder.itemView.setVisibility(View.VISIBLE);
         switch (holder.getItemViewType()) {
             case VIEW_TYPE_ICON: {
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
@@ -256,6 +265,27 @@
                 icon.reset();
                 icon.applyFromApplicationInfo(adapterItem.itemInfo);
                 icon.setOnFocusChangeListener(mIconFocusListener);
+                PrivateProfileManager privateProfileManager = mApps.getPrivateProfileManager();
+                if (privateProfileManager != null) {
+                    // Set the alpha of the private space icon to 0 upon expanding the header so the
+                    // alpha can animate -> 1.
+                    boolean isPrivateSpaceItem =
+                            privateProfileManager.isPrivateSpaceItem(adapterItem);
+                    if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
+                        icon.setAlpha(isPrivateSpaceItem
+                                && privateProfileManager.getAnimationScrolling()
+                                && privateProfileManager.getAnimate()
+                                && privateProfileManager.getCurrentState() == STATE_ENABLED
+                                ? 0 : 1);
+                    }
+                    // Views can still be bounded before the app list is updated hence showing icons
+                    // after collapsing.
+                    if (privateProfileManager.getCurrentState() == STATE_DISABLED
+                            && isPrivateSpaceItem) {
+                        adapterItem.decorationInfo = null;
+                        icon.setVisibility(GONE);
+                    }
+                }
                 break;
             }
             case VIEW_TYPE_EMPTY_SEARCH: {
@@ -269,19 +299,22 @@
             case VIEW_TYPE_PRIVATE_SPACE_HEADER:
                 RelativeLayout psHeaderLayout = holder.itemView.findViewById(
                         R.id.ps_header_layout);
-                assert mPrivateSpaceHeaderViewController != null;
-                assert psHeaderLayout != null;
-                mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout);
+                mApps.getPrivateProfileManager().addPrivateSpaceHeaderViewElements(psHeaderLayout);
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
                 int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
-                if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState()
-                        == STATE_DISABLED) {
+                if (mApps.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) {
                     roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT);
                 }
                 adapterItem.decorationInfo =
                         new SectionDecorationInfo(mActivityContext, roundRegions,
                                 false /* decorateTogether */);
                 break;
+            case VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER:
+                adapterItem = mApps.getAdapterItems().get(position);
+                adapterItem.decorationInfo = mApps.getPrivateProfileManager().getCurrentState()
+                        == STATE_DISABLED ? null : new SectionDecorationInfo(mActivityContext,
+                        ROUND_NOTHING, true /* decorateTogether */);
+                break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
             case VIEW_TYPE_WORK_DISABLED_CARD:
                 // nothing to do
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 1ba5f8e..92c589c 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -34,7 +34,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.launcher3.views.ActivityContext;
 import com.android.systemui.plugins.AllAppsRow;
 import com.android.systemui.plugins.AllAppsRow.OnHeightUpdatedListener;
@@ -225,10 +225,10 @@
         for (FloatingHeaderRow row : mAllRows) {
             row.setup(this, mAllRows, tabsHidden);
         }
-        updateExpectedHeight();
 
         mTabsHidden = tabsHidden;
         maybeSetTabVisibility(VISIBLE);
+        updateExpectedHeight();
         mMainRV = mainRV;
         mWorkRV = workRV;
         mSearchRV = searchRV;
@@ -466,9 +466,14 @@
     }
 
     /**
-     * Returns visible height of FloatingHeaderView contents requiring header protection
+     * Returns visible height of FloatingHeaderView contents requiring header protection or the
+     * expected header protection height.
      */
-    int getPeripheralProtectionHeight() {
+    int getPeripheralProtectionHeight(boolean expected) {
+        if (expected) {
+            return getTabLayout().getBottom() - getPaddingTop() + getPaddingBottom()
+                    - mMaxTranslation;
+        }
         // we only want to show protection when work tab is available and header is either
         // collapsed or animating to/from collapsed state
         if (mTabsHidden || mFloatingRowsCollapsed || !mHeaderCollapsed) {
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 5e48177..63a168e 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -21,7 +21,6 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.statemanager.StateManager;
 
 /**
@@ -43,11 +42,7 @@
 
     @Override
     protected int computeNavBarScrimHeight(WindowInsets insets) {
-        if (Utilities.ATLEAST_Q) {
-            return insets.getTappableElementInsets().bottom;
-        } else {
-            return insets.getStableInsetBottom();
-        }
+        return insets.getTappableElementInsets().bottom;
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
index 8712b84..339e443 100644
--- a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
@@ -43,6 +43,9 @@
         for (int i = 0; i < parent.getChildCount(); i++) {
             View view = parent.getChildAt(i);
             int position = parent.getChildAdapterPosition(view);
+            if (position < 0 || position >= mAppsList.getAdapterItems().size()) {
+                continue;
+            }
             BaseAllAppsAdapter.AdapterItem adapterItem = mAppsList.getAdapterItems().get(position);
             SectionDecorationInfo info = adapterItem.decorationInfo;
             if (info == null) {
@@ -56,7 +59,7 @@
                                 new SectionDecorationHandler.UnionDecorationHandler(
                                         decorationHandler, parent.getPaddingLeft(),
                                         parent.getPaddingRight()));
-                unionHandler.addChild(decorationHandler, view, true /* applyBackground */);
+                unionHandler.addChild(decorationHandler, view);
                 deferredDecorations.put(PRIVATE_APP_SECTION, unionHandler);
             } else {
                 decorationHandler.onFocusDraw(c, view);
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 693681b..7e975df 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -16,27 +16,71 @@
 
 package com.android.launcher3.allapps;
 
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.app.animation.Interpolators;
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedPropertySetter;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.PrivateSpaceInstallAppButtonInfo;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.RecyclerViewFastScroller;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Predicate;
 
 /**
@@ -44,15 +88,30 @@
  * logic in the Personal tab.
  */
 public class PrivateProfileManager extends UserProfileManager {
-
-    private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER;
-    private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key";
-    private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
-    private static final int ANIMATION_DURATION = 2000;
+    private static final int EXPAND_COLLAPSE_DURATION = 800;
+    private static final int SETTINGS_OPACITY_DURATION = 160;
     private final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
+    private final int mPsHeaderHeight;
+    private final RecyclerView.OnScrollListener mOnIdleScrollListener =
+            new RecyclerView.OnScrollListener() {
+        @Override
+        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+            super.onScrollStateChanged(recyclerView, newState);
+            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                mAnimationScrolling = false;
+            }
+        }
+    };
+    private Intent mAppInstallerIntent = new Intent();
     private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
     private boolean mPrivateSpaceSettingsAvailable;
+    private boolean mIsAnimationRunning;
+    private boolean mAnimate;
+    private boolean mAnimationScrolling;
+    private Runnable mOnPSHeaderAdded;
+    @Nullable
+    private RelativeLayout mPSHeader;
 
     public PrivateProfileManager(UserManager userManager,
             ActivityAllAppsContainerView<?> allApps,
@@ -61,7 +120,11 @@
         super(userManager, statsLogManager, userCache);
         mAllApps = allApps;
         mPrivateProfileMatcher = (user) -> userCache.getUserInfo(user).isPrivate();
-        UI_HELPER_EXECUTOR.post(this::setPrivateSpaceSettingsAvailable);
+
+        Context appContext = allApps.getContext().getApplicationContext();
+        UI_HELPER_EXECUTOR.post(() -> initializeInBackgroundThread(appContext));
+        mPsHeaderHeight = mAllApps.getContext().getResources().getDimensionPixelSize(
+                R.dimen.ps_header_height);
     }
 
     /** Adds Private Space Header to the layout. */
@@ -71,53 +134,137 @@
         return adapterItems.size();
     }
 
-    /** Disables quiet mode for Private Space User Profile. */
+    /** Adds Private Space System Apps Divider to the layout. */
+    public int addSystemAppsDivider(List<BaseAllAppsAdapter.AdapterItem> adapterItems) {
+        adapterItems.add(new BaseAllAppsAdapter
+                .AdapterItem(VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER));
+        mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
+        return adapterItems.size();
+    }
+
+    /** Adds Private Space install app button to the layout. */
+    public void addPrivateSpaceInstallAppButton(List<BaseAllAppsAdapter.AdapterItem> adapterItems) {
+        Context context = mAllApps.getContext();
+        // Prepare bitmapInfo
+        Intent.ShortcutIconResource shortcut = Intent.ShortcutIconResource.fromContext(
+                context, com.android.launcher3.R.drawable.private_space_install_app_icon);
+        BitmapInfo bitmapInfo = LauncherIcons.obtain(context).createIconBitmap(shortcut);
+
+        PrivateSpaceInstallAppButtonInfo itemInfo = new PrivateSpaceInstallAppButtonInfo();
+        itemInfo.title = context.getResources().getString(R.string.ps_add_button_label);
+        itemInfo.intent = mAppInstallerIntent;
+        itemInfo.bitmap = bitmapInfo;
+        itemInfo.contentDescription = context.getResources().getString(
+                com.android.launcher3.R.string.ps_add_button_content_description);
+        itemInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+
+        BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
+        item.itemInfo = itemInfo;
+        item.decorationInfo = new SectionDecorationInfo(context, ROUND_NOTHING,
+                /* decorateTogether */ true);
+
+        adapterItems.add(item);
+        mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
+    }
+
+    /**
+     * Disables quiet mode for Private Space User Profile.
+     * When called from search, a runnable is set and executed in the {@link #reset()} method, when
+     * Launcher receives update about profile availability.
+     * The runnable is only executed once, and reset after execution.
+     * In case the method is called again, before the previously set runnable was executed,
+     * the runnable will be updated.
+     */
     public void unlockPrivateProfile() {
-        enableQuietMode(false);
+        setQuietMode(false);
     }
 
     /** Enables quiet mode for Private Space User Profile. */
-    public void lockPrivateProfile() {
-        enableQuietMode(true);
+    void lockPrivateProfile() {
+        setQuietMode(true);
     }
 
     /** Whether private profile should be hidden on Launcher. */
     public boolean isPrivateSpaceHidden() {
         return getCurrentState() == STATE_DISABLED && SettingsCache.INSTANCE
-                    .get(mAllApps.mActivityContext).getValue(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, 0);
+                    .get(mAllApps.getContext()).getValue(PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI, 0);
     }
 
-    /** Resets the current state of Private Profile, w.r.t. to Launcher. */
+    /**
+     * Resets the current state of Private Profile, w.r.t. to Launcher. The decorator should only
+     * be applied upon expand before animating. When collapsing, reset() will remove the decorator
+     * when animation is not running.
+     */
     public void reset() {
+        getMainRecyclerView().setChildAttachedConsumer(null);
+        int previousState = getCurrentState();
         boolean isEnabled = !mAllApps.getAppsStore()
                 .hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
         int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
         setCurrentState(updatedState);
+        if (mPSHeader != null) {
+            mPSHeader.setAlpha(1);
+        }
+        if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
+            postUnlock();
+        } else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
+            executeLock();
+        }
         resetPrivateSpaceDecorator(updatedState);
     }
 
-    /** Opens the Private Space Settings Entry Point. */
-    public void openPrivateSpaceSettings() {
-        Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
-        psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
-        mAllApps.getContext().startActivity(psSettingsIntent);
+    /**
+     * Opens the Private Space Settings Page.
+     *
+     * @param view the view that was clicked to open the settings page and which will be the same
+     *             view to animate back. Otherwise if there is no view, simply start the activity.
+     */
+    public void openPrivateSpaceSettings(View view) {
+        if (mPrivateSpaceSettingsAvailable) {
+            Context context = mAllApps.getContext();
+            Intent intent = ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
+            if (view == null) {
+                context.startActivity(intent);
+                return;
+            }
+            ActivityContext activityContext = ActivityContext.lookupContext(context);
+            AppInfo itemInfo = new AppInfo();
+            itemInfo.id = CONTAINER_PRIVATESPACE;
+            itemInfo.componentName = intent.getComponent();
+            itemInfo.container = CONTAINER_PRIVATESPACE;
+            view.setTag(itemInfo);
+            activityContext.startActivitySafely(view, intent, itemInfo);
+        }
     }
 
-    /** Whether Private Space Settings Entry Point is available on the device. */
+    /** Returns whether or not Private Space Settings Page is available. */
     public boolean isPrivateSpaceSettingsAvailable() {
         return mPrivateSpaceSettingsAvailable;
     }
 
-    private void setPrivateSpaceSettingsAvailable() {
-        if (mPrivateSpaceSettingsAvailable) {
-            return;
-        }
+    /** Sets whether Private Space Settings Page is available. */
+    public boolean setPrivateSpaceSettingsAvailable(boolean value) {
+        return mPrivateSpaceSettingsAvailable = value;
+    }
+
+    /** Initializes binder call based properties in non-main thread.
+     * <p>
+     * This can cause the Private Space container items to not load/respond correctly sometimes,
+     * when the All Apps Container loads for the first time (device restarts, new profiles
+     * added/removed, etc.), as the properties are being set in non-ui thread whereas the container
+     * loads in the ui thread.
+     * This case should still be ok, as locking the Private Space container and unlocking it,
+     * reloads the values, fixing the incorrect UI.
+     */
+    private void initializeInBackgroundThread(Context appContext) {
         Preconditions.assertNonUiThread();
-        Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
-        psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
-        ResolveInfo resolveInfo = mAllApps.getContext().getPackageManager()
-                .resolveActivity(psSettingsIntent, PackageManager.MATCH_SYSTEM_ONLY);
-        mPrivateSpaceSettingsAvailable = resolveInfo != null;
+        ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(appContext);
+        UserHandle profileUser = getProfileUser();
+        if (profileUser != null) {
+            mAppInstallerIntent = apiWrapper
+                    .getAppMarketActivityIntent(BuildConfig.APPLICATION_ID, profileUser);
+        }
+        setPrivateSpaceSettingsAvailable(apiWrapper.getPrivateSpaceSettingsIntent() != null);
     }
 
     @VisibleForTesting
@@ -138,28 +285,482 @@
             }
             // Add Private Space Decorator to the Recycler view.
             mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
-            if (Flags.privateSpaceAnimation() && mAllApps.getActiveRecyclerView()
-                    == mainAdapterHolder.mRecyclerView) {
-                RecyclerViewAnimationController recyclerViewAnimationController =
-                        new RecyclerViewAnimationController(mAllApps);
-                recyclerViewAnimationController.animateToState(true /* expand */,
-                        ANIMATION_DURATION, () -> {});
-            }
         } else {
             // Remove Private Space Decorator from the Recycler view.
-            if (mPrivateAppsSectionDecorator != null) {
+            if (mPrivateAppsSectionDecorator != null && !mIsAnimationRunning) {
                 mainAdapterHolder.mRecyclerView.removeItemDecoration(mPrivateAppsSectionDecorator);
             }
         }
     }
 
-    /** Posts quiet mode enable/disable call for private profile. */
-    private void enableQuietMode(boolean enable) {
-        setQuietMode(enable);
+    @Override
+    public void setQuietMode(boolean enable) {
+        super.setQuietMode(enable);
+        mAnimate = true;
+    }
+
+    /**
+     * Expand the private space after the app list has been added and updated from
+     * {@link AlphabeticalAppsList#onAppsUpdated()}
+     */
+    void postUnlock() {
+        if (mAllApps.isSearching()) {
+            MAIN_EXECUTOR.post(this::exitSearchAndExpand);
+        } else {
+            MAIN_EXECUTOR.post(this::expandPrivateSpace);
+        }
+    }
+
+    /** Collapses the private space before the app list has been updated. */
+    void executeLock() {
+        MAIN_EXECUTOR.execute(() -> updatePrivateStateAnimator(false));
+    }
+
+    void setAnimationRunning(boolean isAnimationRunning) {
+        if (!isAnimationRunning) {
+            mAnimate = false;
+        }
+        mIsAnimationRunning = isAnimationRunning;
+    }
+
+    boolean getAnimationRunning() {
+        return mIsAnimationRunning;
+    }
+
+    private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
+        return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
+    }
+
+    private boolean transitioningFromUnlockedToLocked(int previousState, int updatedState) {
+        return previousState == STATE_ENABLED && updatedState == STATE_DISABLED;
     }
 
     @Override
     public Predicate<UserHandle> getUserMatcher() {
         return mPrivateProfileMatcher;
     }
+
+    /**
+     * Splits private apps into user installed and system apps.
+     * When the list of system apps is empty, all apps are treated as system.
+     */
+    public Predicate<AppInfo> splitIntoUserInstalledAndSystemApps(Context context) {
+        List<String> preInstallApps = UserCache.getInstance(context)
+                .getPreInstallApps(getProfileUser());
+        return appInfo -> !preInstallApps.isEmpty()
+                && (appInfo.componentName == null
+                || !(preInstallApps.contains(appInfo.componentName.getPackageName())));
+    }
+
+    /** Add Private Space Header view elements based upon {@link UserProfileState} */
+    public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+        mPSHeader = parent;
+        if (mOnPSHeaderAdded != null) {
+            MAIN_EXECUTOR.execute(mOnPSHeaderAdded);
+            mOnPSHeaderAdded = null;
+        }
+        // Set the transition duration for the settings and lock button to animate.
+        ViewGroup settingAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
+        if (mAnimate) {
+            enableLayoutTransition(settingAndLockGroup);
+        } else {
+            // Ensure any unwanted animations to not happen.
+            settingAndLockGroup.setLayoutTransition(null);
+        }
+
+        //Add quietMode image and action for lock/unlock button
+        ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
+        assert lockButton != null;
+        addLockButton(lockButton);
+
+        //Trigger lock/unlock action from header.
+        addHeaderOnClickListener(mPSHeader);
+
+        //Add image and action for private space settings button
+        ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
+        assert settingsButton != null;
+        addPrivateSpaceSettingsButton(settingsButton);
+
+        //Add image for private space transitioning view
+        ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
+        assert transitionView != null;
+        addTransitionImage(transitionView);
+    }
+
+    /**
+     *  Adds the quietModeButton and attach onClickListener for the header to animate different
+     *  states when clicked.
+     */
+    private void addLockButton(ViewGroup lockButton) {
+        TextView lockText = lockButton.findViewById(R.id.lock_text);
+        switch (getCurrentState()) {
+            case STATE_ENABLED -> {
+                lockText.setVisibility(VISIBLE);
+                lockButton.setVisibility(VISIBLE);
+                lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
+            }
+            case STATE_DISABLED -> {
+                lockText.setVisibility(GONE);
+                lockButton.setVisibility(VISIBLE);
+                lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
+            }
+            default -> lockButton.setVisibility(GONE);
+        }
+    }
+
+    private void addHeaderOnClickListener(RelativeLayout header) {
+        if (getCurrentState() == STATE_DISABLED) {
+            header.setOnClickListener(view -> lockingAction(/* lock */ false));
+            header.setClickable(true);
+        } else {
+            header.setOnClickListener(null);
+            header.setClickable(false);
+        }
+    }
+
+    /** Sets the enablement of the profile when header or button is clicked. */
+    private void lockingAction(boolean lock) {
+        logEvents(lock ? LAUNCHER_PRIVATE_SPACE_LOCK_TAP : LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
+        if (lock) {
+            lockPrivateProfile();
+        } else {
+            unlockPrivateProfile();
+        }
+    }
+
+    private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
+        if (getCurrentState() == STATE_ENABLED
+                && isPrivateSpaceSettingsAvailable()) {
+            settingsButton.setVisibility(VISIBLE);
+            settingsButton.setAlpha(1f);
+            settingsButton.setOnClickListener(
+                    view -> {
+                        logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
+                        openPrivateSpaceSettings(view);
+                    });
+        } else {
+            settingsButton.setVisibility(GONE);
+        }
+    }
+
+    private void addTransitionImage(ImageView transitionImage) {
+        if (getCurrentState() == STATE_TRANSITION) {
+            transitionImage.setVisibility(VISIBLE);
+        } else {
+            transitionImage.setVisibility(GONE);
+        }
+    }
+
+    /** Finds the private space header to scroll to and set the private space icons to GONE. */
+    private void collapse() {
+        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+        List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
+                allAppsRecyclerView.getApps().getAdapterItems();
+        for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
+            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+            // Scroll to the private space header.
+            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                // Note: SmoothScroller is meant to be used once.
+                RecyclerView.SmoothScroller smoothScroller =
+                        new LinearSmoothScroller(mAllApps.getContext()) {
+                            @Override protected int getVerticalSnapPreference() {
+                                return LinearSmoothScroller.SNAP_TO_END;
+                            }
+                        };
+                smoothScroller.setTargetPosition(i);
+                RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+                if (layoutManager != null) {
+                    startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
+                    currentItem.decorationInfo = null;
+                }
+                break;
+            }
+            // Make the private space apps gone to "collapse".
+            if (isPrivateSpaceItem(currentItem)) {
+                RecyclerView.ViewHolder viewHolder =
+                        allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+                if (viewHolder != null) {
+                    viewHolder.itemView.setVisibility(GONE);
+                    currentItem.decorationInfo = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * Upon expanding, only scroll to the item position in the adapter that allows the header to be
+     * visible.
+     */
+    public int scrollForHeaderToBeVisibleInContainer(
+            AllAppsRecyclerView allAppsRecyclerView,
+            List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
+            int psHeaderHeight,
+            int allAppsCellHeight) {
+        int rowToExpandToWithRespectToHeader = -1;
+        int itemToScrollTo = -1;
+        // Looks for the item in the app list to scroll to so that the header is visible.
+        for (int i = 0; i < appListAdapterItems.size(); i++) {
+            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                itemToScrollTo = i;
+                continue;
+            }
+            if (itemToScrollTo != -1) {
+                itemToScrollTo = i;
+                if (rowToExpandToWithRespectToHeader == -1) {
+                    rowToExpandToWithRespectToHeader = currentItem.rowIndex;
+                }
+                // If there are no tabs, decrease the row to scroll to by 1 since the header
+                // may be cut off slightly.
+                int rowToScrollTo =
+                        (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
+                                - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight)
+                                - (mAllApps.isUsingTabs() ? 0 : 1);
+                int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
+                // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
+                if (currentRowDistance == rowToScrollTo - 1) {
+                    break;
+                }
+            }
+        }
+        if (itemToScrollTo != -1) {
+            // Note: SmoothScroller is meant to be used once.
+            RecyclerView.SmoothScroller smoothScroller =
+                    new LinearSmoothScroller(mAllApps.getContext()) {
+                        @Override protected int getVerticalSnapPreference() {
+                            return LinearSmoothScroller.SNAP_TO_ANY;
+                        }
+                    };
+            smoothScroller.setTargetPosition(itemToScrollTo);
+            RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+            if (layoutManager != null) {
+                startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
+            }
+        }
+        return itemToScrollTo;
+    }
+
+    /**
+     * Scrolls up to the private space header and animates the collapsing of the text.
+     */
+    private ValueAnimator animateCollapseAnimation() {
+        float from = 1;
+        float to = 0;
+        RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
+        ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
+        collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        collapseAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (scrollBar != null) {
+                    scrollBar.setVisibility(INVISIBLE);
+                }
+                // Scroll up to header.
+                collapse();
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                if (scrollBar != null) {
+                    scrollBar.setThumbOffsetY(-1);
+                    scrollBar.setVisibility(VISIBLE);
+                }
+            }
+        });
+        return collapseAnim;
+    }
+
+    private ValueAnimator animateAlphaOfIcons(boolean isExpanding) {
+        float from = isExpanding ? 0 : 1;
+        float to = isExpanding ? 1 : 0;
+        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+        List<BaseAllAppsAdapter.AdapterItem> allAppsAdapterItems =
+                mAllApps.getActiveRecyclerView().getApps().getAdapterItems();
+        ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+        alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                float newAlpha = (float) valueAnimator.getAnimatedValue();
+                for (int i = 0; i < allAppsAdapterItems.size(); i++) {
+                    BaseAllAppsAdapter.AdapterItem currentItem = allAppsAdapterItems.get(i);
+                    if (isPrivateSpaceItem(currentItem) &&
+                            currentItem.viewType != VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                        RecyclerView.ViewHolder viewHolder =
+                                allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+                        if (viewHolder != null) {
+                            viewHolder.itemView.setAlpha(newAlpha);
+                        }
+                    }
+                }
+            }
+        });
+        return alphaAnim;
+    }
+
+    /**
+     * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
+     * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
+     * here.
+     */
+    private void updatePrivateStateAnimator(boolean expand) {
+        if (!Flags.enablePrivateSpace() || !Flags.privateSpaceAnimation()) {
+            return;
+        }
+        if (mPSHeader == null) {
+            mOnPSHeaderAdded = () -> updatePrivateStateAnimator(expand);
+            setAnimationRunning(false);
+            return;
+        }
+        ViewGroup settingsAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
+        ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
+        if (settingsAndLockGroup.getLayoutTransition() == null) {
+            // Set a new transition if the current ViewGroup does not already contain one as each
+            // transition should only happen once when applied.
+            enableLayoutTransition(settingsAndLockGroup);
+        }
+        PropertySetter headerSetter = new AnimatedPropertySetter();
+        ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
+        updateSettingsGearAlpha(settingsButton, expand, headerSetter);
+        AnimatorSet animatorSet = headerSetter.buildAnim();
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // Animate the collapsing of the text at the same time while updating lock button.
+                lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+                setAnimationRunning(true);
+            }
+        });
+        animatorSet.addListener(forEndCallback(() -> {
+            setAnimationRunning(false);
+            getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
+            if (!expand) {
+                // Call onAppsUpdated() because it may be canceled when this animation occurs.
+                mAllApps.getPersonalAppList().onAppsUpdated();
+                if (isPrivateSpaceHidden()) {
+                    // TODO (b/325455879): Figure out if we can avoid this.
+                    getMainRecyclerView().getAdapter().notifyDataSetChanged();
+                }
+            }
+        }));
+        if (expand) {
+            animatorSet.playTogether(animateAlphaOfIcons(true));
+        } else {
+            if (isPrivateSpaceHidden()) {
+                animatorSet.playSequentially(animateAlphaOfIcons(false),
+                        animateCollapseAnimation(), fadeOutHeaderAlpha());
+            } else {
+                animatorSet.playSequentially(animateAlphaOfIcons(false),
+                        animateCollapseAnimation());
+            }
+        }
+        animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
+        animatorSet.start();
+    }
+
+    /** Fades out the private space container. */
+    private ValueAnimator fadeOutHeaderAlpha() {
+        if (mPSHeader == null) {
+            return new ValueAnimator();
+        }
+        float from = 1;
+        float to = 0;
+        ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
+        alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                if (mPSHeader != null) {
+                    mPSHeader.setAlpha((float) valueAnimator.getAnimatedValue());
+                }
+            }
+        });
+        return alphaAnim;
+    }
+
+    /** Animates the layout changes when the text of the button becomes visible/gone. */
+    private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
+        LayoutTransition settingsAndLockTransition = new LayoutTransition();
+        settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
+        settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+        settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
+            @Override
+            public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+            }
+            @Override
+            public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+                settingsAndLockGroup.setLayoutTransition(null);
+                mAnimate = false;
+            }
+        });
+        settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
+    }
+
+    /** Change the settings gear alpha when expanded or collapsed. */
+    private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
+            PropertySetter setter) {
+        float toAlpha = expand ? 1 : 0;
+        setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
+                .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+    }
+
+    void expandPrivateSpace() {
+        // If we are on main adapter view, we apply the PS Container expansion animation and
+        // scroll down to load the entire container, making animation visible.
+        ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
+        List<BaseAllAppsAdapter.AdapterItem> adapterItems =
+                mainAdapterHolder.mAppsList.getAdapterItems();
+        if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
+                && mAllApps.isPersonalTab()) {
+            // Animate the text and settings icon.
+            DeviceProfile deviceProfile =
+                    ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
+            scrollForHeaderToBeVisibleInContainer(mainAdapterHolder.mRecyclerView, adapterItems,
+                    getPsHeaderHeight(), deviceProfile.allAppsCellHeightPx);
+            updatePrivateStateAnimator(true);
+        }
+    }
+
+    private void exitSearchAndExpand() {
+        mAllApps.updateHeaderScroll(0);
+        // Animate to A-Z with 0 time to reset the animation with proper state management.
+        mAllApps.animateToSearchState(false, 0);
+        MAIN_EXECUTOR.post(() -> {
+            mAllApps.mSearchUiManager.resetSearch();
+            mAllApps.switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
+            expandPrivateSpace();
+        });
+    }
+
+    /** Starts the smooth scroll with the provided smoothScroller and add idle listener. */
+    private void startAnimationScroll(AllAppsRecyclerView allAppsRecyclerView,
+            RecyclerView.LayoutManager layoutManager, RecyclerView.SmoothScroller smoothScroller) {
+        mAnimationScrolling = true;
+        layoutManager.startSmoothScroll(smoothScroller);
+        allAppsRecyclerView.removeOnScrollListener(mOnIdleScrollListener);
+        allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
+    }
+
+    AllAppsRecyclerView getMainRecyclerView() {
+        return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
+    }
+
+    boolean getAnimate() {
+        return mAnimate;
+    }
+
+    boolean getAnimationScrolling() {
+        return mAnimationScrolling;
+    }
+
+    int getPsHeaderHeight() {
+        return mPsHeaderHeight;
+    }
+
+    boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
+        return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
+                || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
deleted file mode 100644
index 568ce32..0000000
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
-
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
-
-/**
- * Controller which returns views to be added to Private Space Header based upon
- * {@link UserProfileState}
- */
-public class PrivateSpaceHeaderViewController {
-    private final PrivateProfileManager mPrivateProfileManager;
-
-    public PrivateSpaceHeaderViewController(PrivateProfileManager privateProfileManager) {
-        this.mPrivateProfileManager = privateProfileManager;
-    }
-
-    /** Add Private Space Header view elements based upon {@link UserProfileState} */
-    public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
-        //Add quietMode image and action for lock/unlock button
-        ImageButton quietModeButton = parent.findViewById(R.id.ps_lock_unlock_button);
-        assert quietModeButton != null;
-        addQuietModeButton(quietModeButton);
-
-        //Add image and action for private space settings button
-        ImageButton settingsButton = parent.findViewById(R.id.ps_settings_button);
-        assert settingsButton != null;
-        addPrivateSpaceSettingsButton(settingsButton);
-
-        //Add image for private space transitioning view
-        ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
-        assert transitionView != null;
-        addTransitionImage(transitionView);
-    }
-
-    private void addQuietModeButton(ImageButton quietModeButton) {
-        switch (mPrivateProfileManager.getCurrentState()) {
-            case STATE_ENABLED -> {
-                quietModeButton.setVisibility(View.VISIBLE);
-                quietModeButton.setImageResource(R.drawable.bg_ps_lock_button);
-                quietModeButton.setOnClickListener(
-                        view -> {
-                            mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_LOCK_TAP);
-                            mPrivateProfileManager.lockPrivateProfile();
-                        });
-            }
-            case STATE_DISABLED -> {
-                quietModeButton.setVisibility(View.VISIBLE);
-                quietModeButton.setImageResource(R.drawable.bg_ps_unlock_button);
-                quietModeButton.setOnClickListener(
-                        view -> {
-                            mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
-                            mPrivateProfileManager.unlockPrivateProfile();
-                        });
-            }
-            default -> quietModeButton.setVisibility(View.GONE);
-        }
-    }
-
-    private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
-        if (mPrivateProfileManager.getCurrentState() == STATE_ENABLED
-                && mPrivateProfileManager.isPrivateSpaceSettingsAvailable()) {
-            settingsButton.setVisibility(View.VISIBLE);
-            settingsButton.setOnClickListener(
-                    view -> {
-                        mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
-                        mPrivateProfileManager.openPrivateSpaceSettings();
-                    });
-        } else {
-            settingsButton.setVisibility(View.GONE);
-        }
-    }
-
-    private void addTransitionImage(ImageView transitionImage) {
-        if (mPrivateProfileManager.getCurrentState() == STATE_TRANSITION) {
-            transitionImage.setVisibility(View.VISIBLE);
-        } else {
-            transitionImage.setVisibility(View.GONE);
-        }
-    }
-
-    PrivateProfileManager getPrivateProfileManager() {
-        return mPrivateProfileManager;
-    }
-}
diff --git a/src/com/android/launcher3/allapps/SectionDecorationHandler.java b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
index f79b82c..ac9b146 100644
--- a/src/com/android/launcher3/allapps/SectionDecorationHandler.java
+++ b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
@@ -176,13 +176,10 @@
         /**
          * Expands decoration bounds to include child {@link PrivateAppsSectionDecorator}
          */
-        public void addChild(SectionDecorationHandler child, View view, boolean applyBackground) {
+        public void addChild(SectionDecorationHandler child, View view) {
             int scaledHeight = (int) (view.getHeight() * view.getScaleY());
             mBounds.union(view.getLeft(), view.getY(),
                     view.getRight(), view.getY() + scaledHeight);
-            if (applyBackground) {
-                applyBackground(view, mContext, null, false);
-            }
             mIsBottomRound |= child.mIsBottomRound;
             mIsBottomLeftRound |= child.mIsBottomLeftRound;
             mIsBottomRightRound |= child.mIsBottomRightRound;
diff --git a/src/com/android/launcher3/allapps/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
index 1fed2b6..c438d19 100644
--- a/src/com/android/launcher3/allapps/SectionDecorationInfo.java
+++ b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
@@ -22,11 +22,11 @@
 
 public class SectionDecorationInfo {
 
-    public static final int ROUND_NOTHING = 1 << 1;
-    public static final int ROUND_TOP_LEFT = 1 << 2;
-    public static final int ROUND_TOP_RIGHT = 1 << 3;
-    public static final int ROUND_BOTTOM_LEFT = 1 << 4;
-    public static final int ROUND_BOTTOM_RIGHT = 1 << 5;
+    public static final int ROUND_NOTHING = 0;
+    public static final int ROUND_TOP_LEFT = 1 << 1;
+    public static final int ROUND_TOP_RIGHT = 1 << 2;
+    public static final int ROUND_BOTTOM_LEFT = 1 << 3;
+    public static final int ROUND_BOTTOM_RIGHT = 1 << 4;
     public static final int DECORATOR_ALPHA = 255;
 
     protected boolean mShouldDecorateItemsTogether;
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 0261010..6a1f37a 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -22,9 +22,7 @@
 import android.os.UserManager;
 
 import androidx.annotation.IntDef;
-import androidx.annotation.VisibleForTesting;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.UserCache;
@@ -71,16 +69,13 @@
 
     /** Sets quiet mode as enabled/disabled for the profile type. */
     protected void setQuietMode(boolean enabled) {
-        if (Utilities.ATLEAST_P) {
-            UI_HELPER_EXECUTOR.post(() -> {
+        UI_HELPER_EXECUTOR.post(() ->
                 mUserCache.getUserProfiles()
                         .stream()
                         .filter(getUserMatcher())
                         .findFirst()
                         .ifPresent(userHandle ->
-                                mUserManager.requestQuietModeEnabled(enabled, userHandle));
-            });
-        }
+                                mUserManager.requestQuietModeEnabled(enabled, userHandle)));
     }
 
     /** Sets current state for the profile type. */
@@ -89,11 +84,23 @@
     }
 
     /** Returns current state for the profile type. */
-    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
     public int getCurrentState() {
         return mCurrentState;
     }
 
+    /** Returns if user profile is enabled. */
+    public boolean isEnabled() {
+        return mCurrentState == STATE_ENABLED;
+    }
+
+    /** Returns the UserHandle corresponding to the profile type, null in case no matches found. */
+    public UserHandle getProfileUser() {
+        return mUserCache.getUserProfiles().stream()
+                .filter(getUserMatcher())
+                .findAny()
+                .orElse(null);
+    }
+
     /** Logs Event to StatsLogManager. */
     protected void logEvents(StatsLogManager.EventEnum event) {
         mStatsLogManager.logger().log(event);
diff --git a/src/com/android/launcher3/allapps/WorkEduCard.java b/src/com/android/launcher3/allapps/WorkEduCard.java
index 1059097..5fe2f0c 100644
--- a/src/com/android/launcher3/allapps/WorkEduCard.java
+++ b/src/com/android/launcher3/allapps/WorkEduCard.java
@@ -103,6 +103,8 @@
             AllAppsRecyclerView rv = mActivityContext.getAppsView().mAH.get(
                     ActivityAllAppsContainerView.AdapterHolder.WORK).mRecyclerView;
             rv.getApps().getAdapterItems().remove(mPosition);
+            // Remove the educard fast scroll section.
+            rv.getApps().getFastScrollerSections().remove(0);
             rv.getAdapter().notifyItemRemoved(mPosition);
         }
     }
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index 48400b2..6049574 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,14 +15,10 @@
  */
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
-
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.View;
 import android.view.WindowInsets;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -35,7 +31,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 /**
@@ -53,12 +48,11 @@
     private final Rect mImeInsets = new Rect();
     private int mFlags;
     private final ActivityContext mActivityContext;
+    private final Context mContext;
 
     // Threshold when user scrolls up/down to determine when should button extend/collapse
     private final int mScrollThreshold;
-    private ImageView mIcon;
     private TextView mTextView;
-    private final StatsLogManager mStatsLogManager;
 
 
     public WorkModeSwitch(@NonNull Context context) {
@@ -71,23 +65,20 @@
 
     public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mContext = context;
         mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
         mActivityContext = ActivityContext.lookupContext(getContext());
-        mStatsLogManager = mActivityContext.getStatsLogManager();
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        mIcon = findViewById(R.id.work_icon);
         mTextView = findViewById(R.id.pause_text);
         setSelected(true);
-        if (Utilities.ATLEAST_R) {
-            KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
-                    new KeyboardInsetAnimationCallback(this);
-            setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
-        }
+        KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
+                new KeyboardInsetAnimationCallback(this);
+        setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
 
         setInsets(mActivityContext.getDeviceProfile().getInsets());
         updateStringFromCache();
@@ -116,13 +107,8 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        View parent = (View) getParent();
         boolean isRtl = Utilities.isRtl(getResources());
-        Rect allAppsPadding = mActivityContext.getDeviceProfile().allAppsPadding;
-        int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight()
-                - (allAppsPadding.left + allAppsPadding.right);
-        int tabWidth = getTabWidth(getContext(), size);
-        int shift = (size - tabWidth) / 2 + (isRtl ? allAppsPadding.left : allAppsPadding.right);
+        int shift = mActivityContext.getDeviceProfile().getAllAppsIconStartMargin(mContext);
         setTranslationX(isRtl ? shift : -shift);
     }
 
diff --git a/src/com/android/launcher3/allapps/WorkPausedCard.java b/src/com/android/launcher3/allapps/WorkPausedCard.java
index 1882667..e1eeabe 100644
--- a/src/com/android/launcher3/allapps/WorkPausedCard.java
+++ b/src/com/android/launcher3/allapps/WorkPausedCard.java
@@ -26,7 +26,6 @@
 import android.widget.TextView;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
 
@@ -80,11 +79,9 @@
 
     @Override
     public void onClick(View view) {
-        if (Utilities.ATLEAST_P) {
-            setEnabled(false);
-            mActivityContext.getAppsView().getWorkManager().setWorkProfileEnabled(true);
-            mActivityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
-        }
+        setEnabled(false);
+        mActivityContext.getAppsView().getWorkManager().setWorkProfileEnabled(true);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_ON_WORK_APPS_TAP);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index c430a36..96998a3 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -73,7 +73,7 @@
      * Posts quite mode enable/disable call for work profile user
      */
     public void setWorkProfileEnabled(boolean enabled) {
-        setCurrentState(STATE_TRANSITION);
+        updateCurrentState(STATE_TRANSITION);
         setQuietMode(!enabled);
     }
 
@@ -199,8 +199,7 @@
     }
 
     private void onWorkFabClicked(View view) {
-        if (Utilities.ATLEAST_P && getCurrentState() == STATE_ENABLED
-                && mWorkModeSwitch.isEnabled()) {
+        if (getCurrentState() == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
             logEvents(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
             setWorkProfileEnabled(false);
         }
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 4427a49..19c3ebe 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -20,6 +20,7 @@
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.text.style.SuggestionSpan;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
@@ -30,7 +31,6 @@
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.search.SearchAlgorithm;
 import com.android.launcher3.search.SearchCallback;
 import com.android.launcher3.views.ActivityContext;
@@ -42,6 +42,7 @@
         implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener,
         OnFocusChangeListener {
 
+    private static final String TAG = "AllAppsSearchBarController";
     protected ActivityContext mLauncher;
     protected SearchCallback<AdapterItem> mCallback;
     protected ExtendedEditText mInput;
@@ -122,6 +123,7 @@
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
 
         if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_GO) {
+            Log.i(TAG, "User tapped ime search button");
             // selectFocusedView should return SearchTargetEvent that is passed onto onClick
             return mLauncher.getAppsView().getMainAdapterProvider().launchHighlightedItem();
         }
@@ -141,7 +143,7 @@
 
     @Override
     public void onFocusChange(View view, boolean hasFocus) {
-        if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+        if (!hasFocus) {
             mInput.hideKeyboard();
         }
     }
@@ -152,6 +154,7 @@
     public void reset() {
         mCallback.clearSearchResult();
         mInput.reset();
+        mInput.clearFocus();
         mQuery = null;
         mInput.removeOnFocusChangeListener(this);
     }
diff --git a/src/com/android/launcher3/anim/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java
index 2f3fa63..b414ab6 100644
--- a/src/com/android/launcher3/anim/AnimatedFloat.java
+++ b/src/com/android/launcher3/anim/AnimatedFloat.java
@@ -109,6 +109,13 @@
     public void cancelAnimation() {
         if (mValueAnimator != null) {
             mValueAnimator.cancel();
+            // Clears the property values, so further ObjectAnimator#setCurrentFraction from e.g.
+            // AnimatorPlaybackController calls would do nothing. The null check is necessary to
+            // avoid mValueAnimator being set to null in onAnimationEnd.
+            if (mValueAnimator != null) {
+                mValueAnimator.setValues();
+                mValueAnimator = null;
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index fd731f4..e58890f 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -25,7 +25,6 @@
 import android.os.Trace;
 import android.util.FloatProperty;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController.Holder;
 
 import java.util.ArrayList;
@@ -84,9 +83,23 @@
         add(anim);
     }
 
+    /**
+     * Add an {@link AnimatedFloat} to the animation.
+     * <p>
+     * Different from {@link #addFloat}, this method use animator provided by
+     * {@link AnimatedFloat#animateToValue}, which tracks the animator inside the AnimatedFloat,
+     * allowing the animation to be canceled and animate again from AnimatedFloat side.
+     */
+    public void addAnimatedFloat(AnimatedFloat target, float from, float to,
+            TimeInterpolator interpolator) {
+        Animator anim = target.animateToValue(from, to);
+        anim.setInterpolator(interpolator);
+        add(anim);
+    }
+
     /** If trace is enabled, add counter to trace animation progress. */
     public void logAnimationProgressToTrace(String counterName) {
-        if (Utilities.ATLEAST_Q && Trace.isEnabled()) {
+        if (Trace.isEnabled()) {
             super.addOnFrameListener(
                     animation -> Trace.setCounter(
                             counterName, (long) (animation.getAnimatedFraction() * 100)));
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 1d73441..1f73241 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -16,11 +16,13 @@
 
 package com.android.launcher3.apppairs;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
+
 import android.content.Context;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
@@ -28,15 +30,18 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Reorderable;
 import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.views.ActivityContext;
 
-import java.util.Collections;
 import java.util.Comparator;
+import java.util.function.Predicate;
 
 /**
  * A {@link android.widget.FrameLayout} used to represent an app pair icon on the workspace.
@@ -45,12 +50,17 @@
  * member apps are set into these rectangles.
  */
 public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
+    private static final String TAG = "AppPairIcon";
+
     // A view that holds the app pair icon graphic.
     private AppPairIconGraphic mIconGraphic;
     // A view that holds the app pair's title.
     private BubbleTextView mAppPairName;
     // The underlying ItemInfo that stores info about the app pair members, etc.
-    private FolderInfo mInfo;
+    private AppPairInfo mInfo;
+    // The containing element that holds this icon: workspace, taskbar, folder, etc. Affects certain
+    // aspects of how the icon is drawn.
+    private int mContainer;
 
     // Required for Reorderable -- handles translation and bouncing movements
     private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
@@ -68,7 +78,7 @@
      * Builds an AppPairIcon to be added to the Launcher.
      */
     public static AppPairIcon inflateIcon(int resId, ActivityContext activity,
-            @Nullable ViewGroup group, FolderInfo appPairInfo) {
+            @Nullable ViewGroup group, AppPairInfo appPairInfo, int container) {
         DeviceProfile grid = activity.getDeviceProfile();
         LayoutInflater inflater = (group != null)
                 ? LayoutInflater.from(group.getContext())
@@ -76,38 +86,66 @@
         AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false);
 
         // Sort contents, so that left-hand app comes first
-        Collections.sort(appPairInfo.contents, Comparator.comparingInt(a -> a.rank));
+        appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank));
 
-        icon.setClipToPadding(false);
         icon.setTag(appPairInfo);
         icon.setOnClickListener(activity.getItemOnClickListener());
         icon.mInfo = appPairInfo;
+        icon.mContainer = container;
 
         // Set up icon drawable area
         icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
-        icon.mIconGraphic.init(activity.getDeviceProfile(), icon);
+        icon.mIconGraphic.init(icon, container);
 
         // Set up app pair title
         icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
-        icon.mAppPairName.setCompoundDrawablePadding(0);
         FrameLayout.LayoutParams lp =
                 (FrameLayout.LayoutParams) icon.mAppPairName.getLayoutParams();
-        lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
-        icon.mAppPairName.setText(appPairInfo.title);
+        // Shift the title text down to leave room for the icon graphic. Since the icon graphic is
+        // a separate element (and not set as a CompoundDrawable on the BubbleTextView), we need to
+        // shift the text down manually.
+        lp.topMargin = container == DISPLAY_FOLDER
+                ? grid.folderChildIconSizePx + grid.folderChildDrawablePaddingPx
+                : grid.iconSizePx + grid.iconDrawablePaddingPx;
+        // For some reason, app icons have setIncludeFontPadding(false) inside folders, so we set it
+        // here to match that.
+        icon.mAppPairName.setIncludeFontPadding(container != DISPLAY_FOLDER);
+        // Set title text and accessibility title text.
+        icon.updateTitleAndA11yTitle();
 
-        // Set up accessibility
-        icon.setContentDescription(icon.getAccessibilityTitle(
-                appPairInfo.contents.get(0).title, appPairInfo.contents.get(1).title));
         icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
 
         return icon;
     }
 
     /**
-     * Returns a formatted accessibility title for app pairs.
+     * Updates the title and a11y title of the app pair. Called on creation and when packages
+     * change, to reflect app name changes or user language changes.
      */
-    public String getAccessibilityTitle(CharSequence app1, CharSequence app2) {
-        return getContext().getString(R.string.app_pair_name_format, app1, app2);
+    public void updateTitleAndA11yTitle() {
+        updateTitleAndTextView();
+        updateAccessibilityTitle();
+    }
+
+    /**
+     * Updates AppPairInfo with a formatted app pair title, and sets it on the BubbleTextView.
+     */
+    public void updateTitleAndTextView() {
+        CharSequence newTitle = getInfo().generateTitle(getContext());
+        mAppPairName.setText(newTitle);
+    }
+
+    /**
+     * Updates the accessibility title with a formatted string template.
+     */
+    public void updateAccessibilityTitle() {
+        CharSequence app1 = getInfo().getFirstApp().title;
+        CharSequence app2 = getInfo().getSecondApp().title;
+        String a11yTitle = getContext().getString(R.string.app_pair_name_format, app1, app2);
+        setContentDescription(
+                getInfo().shouldReportDisabled(getContext())
+                        ? getContext().getString(R.string.disabled_app_label, a11yTitle)
+                        : a11yTitle);
     }
 
     // Required for DraggableView
@@ -151,11 +189,58 @@
         return mScaleForReorderBounce;
     }
 
-    public FolderInfo getInfo() {
+    public AppPairInfo getInfo() {
         return mInfo;
     }
 
-    public View getIconDrawableArea() {
+    public BubbleTextView getTitleTextView() {
+        return mAppPairName;
+    }
+
+    public AppPairIconGraphic getIconDrawableArea() {
         return mIconGraphic;
     }
+
+    public int getContainer() {
+        return mContainer;
+    }
+
+    /**
+     * Ensures that both app icons in the pair are loaded in high resolution.
+     */
+    public void verifyHighRes() {
+        IconCache iconCache = LauncherAppState.getInstance(getContext()).getIconCache();
+        getInfo().fetchHiResIconsIfNeeded(iconCache);
+    }
+
+    /**
+     * Called when WorkspaceItemInfos get updated, and the app pair icon may need to be redrawn.
+     */
+    public void maybeRedrawForWorkspaceUpdate(Predicate<ItemInfo> itemCheck) {
+        // If either of the app pair icons return true on the predicate (i.e. in the list of
+        // updated apps), redraw the icon graphic (icon background and both icons).
+        if (getInfo().anyMatch(itemCheck)) {
+            updateTitleAndA11yTitle();
+            mIconGraphic.redraw();
+        }
+    }
+
+    /**
+     * Inside folders, icons are vertically centered in their rows. See
+     * {@link BubbleTextView} for comparison.
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mContainer == DISPLAY_FOLDER) {
+            int height = MeasureSpec.getSize(heightMeasureSpec);
+            ActivityContext activity = ActivityContext.lookupContext(getContext());
+            Paint.FontMetrics fm = mAppPairName.getPaint().getFontMetrics();
+            int cellHeightPx = activity.getDeviceProfile().folderChildIconSizePx
+                    + activity.getDeviceProfile().folderChildDrawablePaddingPx
+                    + (int) Math.ceil(fm.bottom - fm.top);
+            setPadding(getPaddingLeft(), (height - cellHeightPx) / 2, getPaddingRight(),
+                    getPaddingBottom());
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
 }
diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
deleted file mode 100644
index 4e60ece..0000000
--- a/src/com/android/launcher3/apppairs/AppPairIconBackground.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.apppairs;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-
-import com.android.launcher3.R;
-
-/**
- * A Drawable for the background behind the twin app icons (looks like two rectangles).
- */
-class AppPairIconBackground extends Drawable {
-    // The underlying view that we are drawing this background on.
-    private final AppPairIconGraphic icon;
-    private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-    /**
-     * Null values to use with
-     * {@link Canvas#drawDoubleRoundRect(RectF, float[], RectF, float[], Paint)}, since there
-     * doesn't seem to be any other API for drawing rectangles with 4 different corner radii.
-     */
-    private static final RectF EMPTY_RECT = new RectF();
-    private static final float[] ARRAY_OF_ZEROES = new float[8];
-
-    AppPairIconBackground(Context context, AppPairIconGraphic iconGraphic) {
-        icon = iconGraphic;
-        // Set up background paint color
-        TypedArray ta = context.getTheme().obtainStyledAttributes(R.styleable.FolderIconPreview);
-        mBackgroundPaint.setStyle(Paint.Style.FILL);
-        mBackgroundPaint.setColor(
-                ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0));
-        ta.recycle();
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        if (icon.isLeftRightSplit()) {
-            drawLeftRightSplit(canvas);
-        } else {
-            drawTopBottomSplit(canvas);
-        }
-    }
-
-    /**
-     * When device is in landscape, we draw the rectangles with a left-right split.
-     */
-    private void drawLeftRightSplit(Canvas canvas) {
-        // Get the bounds where we will draw the background image
-        int width = getBounds().width();
-        int height = getBounds().height();
-
-        // The left half of the background image, excluding center channel
-        RectF leftSide = new RectF(
-                0,
-                0,
-                (width / 2f) - (icon.getCenterChannelSize() / 2f),
-                height
-        );
-        // The right half of the background image, excluding center channel
-        RectF rightSide = new RectF(
-                (width / 2f) + (icon.getCenterChannelSize() / 2f),
-                0,
-                width,
-                height
-        );
-
-        drawCustomRoundedRect(canvas, leftSide, new float[]{
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getBigRadius(), icon.getBigRadius()});
-        drawCustomRoundedRect(canvas, rightSide, new float[]{
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius()});
-    }
-
-    /**
-     * When device is in portrait, we draw the rectangles with a top-bottom split.
-     */
-    private void drawTopBottomSplit(Canvas canvas) {
-        // Get the bounds where we will draw the background image
-        int width = getBounds().width();
-        int height = getBounds().height();
-
-        // The top half of the background image, excluding center channel
-        RectF topSide = new RectF(
-                0,
-                0,
-                width,
-                (height / 2f) - (icon.getCenterChannelSize() / 2f)
-        );
-        // The bottom half of the background image, excluding center channel
-        RectF bottomSide = new RectF(
-                0,
-                (height / 2f) + (icon.getCenterChannelSize() / 2f),
-                width,
-                height
-        );
-
-        drawCustomRoundedRect(canvas, topSide, new float[]{
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius()});
-        drawCustomRoundedRect(canvas, bottomSide, new float[]{
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getSmallRadius(), icon.getSmallRadius(),
-                icon.getBigRadius(), icon.getBigRadius(),
-                icon.getBigRadius(), icon.getBigRadius()});
-    }
-
-    /**
-     * Draws a rectangle with custom rounded corners.
-     * @param c The Canvas to draw on.
-     * @param rect The bounds of the rectangle.
-     * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top
-     *              right y, bottom right x, and so on.
-     */
-    private void drawCustomRoundedRect(Canvas c, RectF rect, float[] radii) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
-            // Canvas.drawDoubleRoundRect is supported from Q onward
-            c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint);
-        } else {
-            // Fallback rectangle with uniform rounded corners
-            c.drawRoundRect(rect, icon.getBigRadius(), icon.getBigRadius(), mBackgroundPaint);
-        }
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.OPAQUE;
-    }
-
-    @Override
-    public void setAlpha(int i) {
-        // Required by Drawable but not used.
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) {
-        // Required by Drawable but not used.
-    }
-}
diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawable.java b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java
new file mode 100644
index 0000000..db83d91
--- /dev/null
+++ b/src/com/android/launcher3/apppairs/AppPairIconDrawable.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.apppairs;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.icons.FastBitmapDrawable;
+
+/**
+ * A composed Drawable consisting of the two app pair icons and the background behind them (looks
+ * like two rectangles).
+ */
+public class AppPairIconDrawable extends Drawable {
+    private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final AppPairIconDrawingParams mP;
+    private final FastBitmapDrawable mIcon1;
+    private final FastBitmapDrawable mIcon2;
+
+    /**
+     * Null values to use with
+     * {@link Canvas#drawDoubleRoundRect(RectF, float[], RectF, float[], Paint)}, since there
+     * doesn't seem to be any other API for drawing rectangles with 4 different corner radii.
+     */
+    private static final RectF EMPTY_RECT = new RectF();
+    private static final float[] ARRAY_OF_ZEROES = new float[8];
+
+    AppPairIconDrawable(
+            AppPairIconDrawingParams p, FastBitmapDrawable icon1, FastBitmapDrawable icon2) {
+        mP = p;
+        mBackgroundPaint.setStyle(Paint.Style.FILL);
+        mBackgroundPaint.setColor(p.getBgColor());
+        mIcon1 = icon1;
+        mIcon2 = icon2;
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        if (mP.isLeftRightSplit()) {
+            drawLeftRightSplit(canvas);
+        } else {
+            drawTopBottomSplit(canvas);
+        }
+
+        canvas.translate(
+                mP.getStandardIconPadding() + mP.getOuterPadding(),
+                mP.getStandardIconPadding() + mP.getOuterPadding()
+        );
+
+        // Draw first icon.
+        canvas.save();
+        // The app icons are placed differently depending on device orientation.
+        if (mP.isLeftRightSplit()) {
+            canvas.translate(
+                    mP.getInnerPadding(),
+                    mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f
+            );
+        } else {
+            canvas.translate(
+                    mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f,
+                    mP.getInnerPadding()
+            );
+        }
+
+        mIcon1.draw(canvas);
+        canvas.restore();
+
+        // Draw second icon.
+        canvas.save();
+        // The app icons are placed differently depending on device orientation.
+        if (mP.isLeftRightSplit()) {
+            canvas.translate(
+                    mP.getBackgroundSize() - (mP.getInnerPadding() + mP.getMemberIconSize()),
+                    mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f
+            );
+        } else {
+            canvas.translate(
+                    mP.getBackgroundSize() / 2f - mP.getMemberIconSize() / 2f,
+                    mP.getBackgroundSize() - (mP.getInnerPadding() + mP.getMemberIconSize())
+            );
+        }
+
+        mIcon2.draw(canvas);
+        canvas.restore();
+    }
+
+    /**
+     * When device is in landscape, we draw the rectangles with a left-right split.
+     */
+    private void drawLeftRightSplit(Canvas canvas) {
+        // Get the bounds where we will draw the background image
+        int width = mP.getIconSize();
+        int height = mP.getIconSize();
+
+        // The left half of the background image, excluding center channel
+        RectF leftSide = new RectF(
+                mP.getStandardIconPadding() + mP.getOuterPadding(),
+                mP.getStandardIconPadding() + mP.getOuterPadding(),
+                (width / 2f) - (mP.getCenterChannelSize() / 2f),
+                height - (mP.getStandardIconPadding() + mP.getOuterPadding())
+        );
+        // The right half of the background image, excluding center channel
+        RectF rightSide = new RectF(
+                (width / 2f) + (mP.getCenterChannelSize() / 2f),
+                (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                width - (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                height - (mP.getStandardIconPadding() + mP.getOuterPadding())
+        );
+
+        drawCustomRoundedRect(canvas, leftSide, new float[]{
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getBigRadius(), mP.getBigRadius()});
+        drawCustomRoundedRect(canvas, rightSide, new float[]{
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius()});
+    }
+
+    /**
+     * When device is in portrait, we draw the rectangles with a top-bottom split.
+     */
+    private void drawTopBottomSplit(Canvas canvas) {
+        // Get the bounds where we will draw the background image
+        int width = mP.getIconSize();
+        int height = mP.getIconSize();
+
+        // The top half of the background image, excluding center channel
+        RectF topSide = new RectF(
+                (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                width - (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                (height / 2f) - (mP.getCenterChannelSize() / 2f)
+        );
+        // The bottom half of the background image, excluding center channel
+        RectF bottomSide = new RectF(
+                (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                (height / 2f) + (mP.getCenterChannelSize() / 2f),
+                width - (mP.getStandardIconPadding() + mP.getOuterPadding()),
+                height - (mP.getStandardIconPadding() + mP.getOuterPadding())
+        );
+
+        drawCustomRoundedRect(canvas, topSide, new float[]{
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius()});
+        drawCustomRoundedRect(canvas, bottomSide, new float[]{
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getSmallRadius(), mP.getSmallRadius(),
+                mP.getBigRadius(), mP.getBigRadius(),
+                mP.getBigRadius(), mP.getBigRadius()});
+    }
+
+    /**
+     * Draws a rectangle with custom rounded corners.
+     * @param c The Canvas to draw on.
+     * @param rect The bounds of the rectangle.
+     * @param radii An array of 8 radii for the corners: top left x, top left y, top right x, top
+     *              right y, bottom right x, and so on.
+     */
+    private void drawCustomRoundedRect(Canvas c, RectF rect, float[] radii) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            // Canvas.drawDoubleRoundRect is supported from Q onward
+            c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint);
+        } else {
+            // Fallback rectangle with uniform rounded corners
+            c.drawRoundRect(rect, mP.getBigRadius(), mP.getBigRadius(), mBackgroundPaint);
+        }
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.OPAQUE;
+    }
+
+    @Override
+    public void setAlpha(int i) {
+        mBackgroundPaint.setAlpha(i);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mBackgroundPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mP.getIconSize();
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mP.getIconSize();
+    }
+}
diff --git a/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt
new file mode 100644
index 0000000..45dc013
--- /dev/null
+++ b/src/com/android/launcher3/apppairs/AppPairIconDrawingParams.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.apppairs
+
+import android.content.Context
+import com.android.launcher3.BubbleTextView.DISPLAY_FOLDER
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
+import com.android.launcher3.util.Themes
+import com.android.launcher3.views.ActivityContext
+
+class AppPairIconDrawingParams(val context: Context, container: Int) {
+    companion object {
+        // Design specs -- the below ratios are in relation to the size of a standard app icon.
+        // Note: The standard app icon has two sizes. One is the full size of the drawable (returned
+        // by dp.iconSizePx), and one is the visual size of the icon on-screen (11/12 of that).
+        // Hence the calculations below.
+        const val STANDARD_ICON_PADDING = 1 / 24f
+        const val STANDARD_ICON_SHRINK = 1 - STANDARD_ICON_PADDING * 2
+        // App pairs are slightly smaller than the *visual* size of a standard icon, so all ratios
+        // are calculated with that in mind.
+        const val OUTER_PADDING_SCALE = 1 / 30f * STANDARD_ICON_SHRINK
+        const val INNER_PADDING_SCALE = 1 / 24f * STANDARD_ICON_SHRINK
+        const val CENTER_CHANNEL_SCALE = 1 / 30f * STANDARD_ICON_SHRINK
+        const val BIG_RADIUS_SCALE = 1 / 5f * STANDARD_ICON_SHRINK
+        const val SMALL_RADIUS_SCALE = 1 / 15f * STANDARD_ICON_SHRINK
+        const val MEMBER_ICON_SCALE = 11 / 30f * STANDARD_ICON_SHRINK
+    }
+
+    // The size at which this graphic will be drawn.
+    val iconSize: Int
+    // Standard app icons are padded by this amount on each side.
+    val standardIconPadding: Float
+    // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
+    // each side.
+    val outerPadding: Float
+    // The colored background (two rectangles in a square area) is this big.
+    val backgroundSize: Float
+    // The size of the channel between the two halves of the app pair icon.
+    val centerChannelSize: Float
+    // The corner radius of the outside corners.
+    val bigRadius: Float
+    // The corner radius of the inside corners, touching the center channel.
+    val smallRadius: Float
+    // Inside of the icon, the two member apps are padded by this much.
+    val innerPadding: Float
+    // The two member apps have icons that are this big (in diameter).
+    val memberIconSize: Float
+    // The app pair icon appears differently in portrait and landscape.
+    var isLeftRightSplit: Boolean = true
+    // The background paint color (based on container).
+    var bgColor: Int = 0
+
+    init {
+        val activity: ActivityContext = ActivityContext.lookupContext(context)
+        val dp = activity.deviceProfile
+        iconSize = if (container == DISPLAY_FOLDER) dp.folderChildIconSizePx else dp.iconSizePx
+        standardIconPadding = iconSize * STANDARD_ICON_PADDING
+        outerPadding = iconSize * OUTER_PADDING_SCALE
+        backgroundSize = iconSize * STANDARD_ICON_SHRINK - (outerPadding * 2)
+        centerChannelSize = iconSize * CENTER_CHANNEL_SCALE
+        bigRadius = iconSize * BIG_RADIUS_SCALE
+        smallRadius = iconSize * SMALL_RADIUS_SCALE
+        innerPadding = iconSize * INNER_PADDING_SCALE
+        memberIconSize = iconSize * MEMBER_ICON_SCALE
+        updateOrientation(dp)
+        updateBgColor(container)
+    }
+
+    /** Checks the device orientation and updates isLeftRightSplit accordingly. */
+    fun updateOrientation(dp: DeviceProfile) {
+        isLeftRightSplit = dp.isLeftRightSplit
+    }
+
+    fun updateBgColor(container: Int) {
+        if (container == DISPLAY_FOLDER) {
+            bgColor = Themes.getAttrColor(context, R.attr.appPairSurfaceInFolder)
+        } else {
+            val ta = context.theme.obtainStyledAttributes(R.styleable.FolderIconPreview)
+            bgColor = ta.getColor(R.styleable.FolderIconPreview_folderPreviewColor, 0)
+            ta.recycle()
+        }
+    }
+}
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index 2945979..dce97eb 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -19,123 +19,124 @@
 import android.content.Context
 import android.graphics.Canvas
 import android.graphics.Rect
-import android.graphics.drawable.Drawable
 import android.util.AttributeSet
 import android.view.Gravity
 import android.widget.FrameLayout
+import androidx.annotation.OpenForTesting
 import com.android.launcher3.DeviceProfile
+import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
+import com.android.launcher3.icons.BitmapInfo
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.util.Themes
+import com.android.launcher3.views.ActivityContext
 
 /**
  * A FrameLayout marking the area on an [AppPairIcon] where the visual icon will be drawn. One of
  * two child UI elements on an [AppPairIcon], along with a BubbleTextView holding the text title.
  */
-class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
-    FrameLayout(context, attrs) {
-    companion object {
-        // Design specs -- the below ratios are in relation to the size of a standard app icon.
-        private const val OUTER_PADDING_SCALE = 1 / 30f
-        private const val INNER_PADDING_SCALE = 1 / 24f
-        private const val MEMBER_ICON_SCALE = 11 / 30f
-        private const val CENTER_CHANNEL_SCALE = 1 / 30f
-        private const val BIG_RADIUS_SCALE = 1 / 5f
-        private const val SMALL_RADIUS_SCALE = 1 / 15f
-    }
+@OpenForTesting
+open class AppPairIconGraphic
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) :
+    FrameLayout(context, attrs), OnDeviceProfileChangeListener {
+    private val TAG = "AppPairIconGraphic"
 
-    // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
-    // each side.
-    private var outerPadding = 0f
-    // Inside of the icon, the two member apps are padded by this much.
-    private var innerPadding = 0f
-    // The colored background (two rectangles in a square area) is this big.
-    private var backgroundSize = 0f
-    // The two member apps have icons that are this big (in diameter).
-    private var memberIconSize = 0f
-    // The size of the center channel.
-    var centerChannelSize = 0f
-    // The large outer radius of the background rectangles.
-    var bigRadius = 0f
-    // The small inner radius of the background rectangles.
-    var smallRadius = 0f
-    // The app pairs icon appears differently in portrait and landscape.
-    var isLeftRightSplit = false
+    companion object {
+        /** Composes a drawable for this icon, consisting of a background and 2 app icons. */
+        @JvmStatic
+        fun composeDrawable(
+            appPairInfo: AppPairInfo,
+            p: AppPairIconDrawingParams
+        ): AppPairIconDrawable {
+            // Generate new icons, using themed flag if needed.
+            val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0
+            val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, flags)
+            val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, flags)
+            appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
+            appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
+
+            // If icons are unlaunchable due to screen size, manually override disabled appearance.
+            // (otherwise, leave disabled state alone; icons will naturally inherit the app's state)
+            val (isApp1Launchable, isApp2Launchable) = appPairInfo.isLaunchable(p.context)
+            if (!isApp1Launchable) appIcon1.setIsDisabled(true)
+            if (!isApp2Launchable) appIcon2.setIsDisabled(true)
+
+            // Create icon drawable.
+            val fullIconDrawable = AppPairIconDrawable(p, appIcon1, appIcon2)
+            fullIconDrawable.setBounds(0, 0, p.iconSize, p.iconSize)
+
+            return fullIconDrawable
+        }
+    }
 
     private lateinit var parentIcon: AppPairIcon
-    private lateinit var appPairBackground: Drawable
-    private lateinit var appIcon1: Drawable
-    private lateinit var appIcon2: Drawable
+    private lateinit var drawParams: AppPairIconDrawingParams
+    lateinit var drawable: AppPairIconDrawable
 
-    fun init(grid: DeviceProfile, icon: AppPairIcon) {
-        // Calculate device-specific measurements
-        val defaultIconSize = grid.iconSizePx
-        outerPadding = OUTER_PADDING_SCALE * defaultIconSize
-        innerPadding = INNER_PADDING_SCALE * defaultIconSize
-        backgroundSize = defaultIconSize - outerPadding * 2
-        memberIconSize = MEMBER_ICON_SCALE * defaultIconSize
-        centerChannelSize = CENTER_CHANNEL_SCALE * defaultIconSize
-        bigRadius = BIG_RADIUS_SCALE * defaultIconSize
-        smallRadius = SMALL_RADIUS_SCALE * defaultIconSize
-        isLeftRightSplit = grid.isLeftRightSplit
+    fun init(icon: AppPairIcon, container: Int) {
         parentIcon = icon
-
-        appPairBackground = AppPairIconBackground(context, this)
-        appPairBackground.setBounds(0, 0, backgroundSize.toInt(), backgroundSize.toInt())
-        appIcon1 = parentIcon.info.contents[0].newIcon(context)
-        appIcon2 = parentIcon.info.contents[1].newIcon(context)
-        appIcon1.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
-        appIcon2.setBounds(0, 0, memberIconSize.toInt(), memberIconSize.toInt())
-    }
-
-    /** Gets this icon graphic's bounds, with respect to the parent icon's coordinate system. */
-    fun getIconBounds(outBounds: Rect) {
-        outBounds.set(0, 0, backgroundSize.toInt(), backgroundSize.toInt())
-        outBounds.offset(
-            // x-coordinate in parent's coordinate system
-            ((parentIcon.width - backgroundSize) / 2).toInt(),
-            // y-coordinate in parent's coordinate system
-            parentIcon.paddingTop + outerPadding.toInt()
-        )
-    }
-
-    override fun dispatchDraw(canvas: Canvas) {
-        super.dispatchDraw(canvas)
+        drawParams = AppPairIconDrawingParams(context, container)
+        drawable = composeDrawable(icon.info, drawParams)
 
         // Center the drawable area in the larger icon canvas
         val lp: LayoutParams = layoutParams as LayoutParams
         lp.gravity = Gravity.CENTER_HORIZONTAL
-        lp.topMargin = outerPadding.toInt()
-        lp.height = backgroundSize.toInt()
-        lp.width = backgroundSize.toInt()
+        lp.height = drawParams.iconSize
+        lp.width = drawParams.iconSize
         layoutParams = lp
+    }
 
-        // Draw background
-        appPairBackground.draw(canvas)
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        getActivityContext().addOnDeviceProfileChangeListener(this)
+    }
 
-        // Draw first icon
-        canvas.save()
-        // The app icons are placed differently depending on device orientation.
-        if (isLeftRightSplit) {
-            canvas.translate(innerPadding, height / 2f - memberIconSize / 2f)
-        } else {
-            canvas.translate(width / 2f - memberIconSize / 2f, innerPadding)
-        }
-        appIcon1.draw(canvas)
-        canvas.restore()
+    override fun onDetachedFromWindow() {
+        super.onDetachedFromWindow()
+        getActivityContext().removeOnDeviceProfileChangeListener(this)
+    }
 
-        // Draw second icon
-        canvas.save()
-        // The app icons are placed differently depending on device orientation.
-        if (isLeftRightSplit) {
-            canvas.translate(
-                width - (innerPadding + memberIconSize),
-                height / 2f - memberIconSize / 2f
-            )
-        } else {
-            canvas.translate(
-                width / 2f - memberIconSize / 2f,
-                height - (innerPadding + memberIconSize)
-            )
-        }
-        appIcon2.draw(canvas)
-        canvas.restore()
+    private fun getActivityContext(): ActivityContext {
+        return ActivityContext.lookupContext(context)
+    }
+
+    /** When device profile changes, update orientation */
+    override fun onDeviceProfileChanged(dp: DeviceProfile) {
+        drawParams.updateOrientation(dp)
+        redraw()
+    }
+
+    /**
+     * When the icon is temporary moved to a different colored surface, update the background color.
+     * Calling this method with [null] reverts the icon back to its default color.
+     */
+    fun onTemporaryContainerChange(newContainer: Int?) {
+        drawParams.updateBgColor(newContainer ?: parentIcon.container)
+        redraw()
+    }
+
+    /**
+     * Gets this icon graphic's visual bounds, with respect to the parent icon's coordinate system.
+     */
+    fun getIconBounds(outBounds: Rect) {
+        outBounds.set(0, 0, drawParams.backgroundSize.toInt(), drawParams.backgroundSize.toInt())
+        outBounds.offset(
+            // x-coordinate in parent's coordinate system
+            ((parentIcon.width - drawParams.backgroundSize) / 2).toInt(),
+            // y-coordinate in parent's coordinate system
+            (parentIcon.paddingTop + drawParams.standardIconPadding + drawParams.outerPadding)
+                .toInt()
+        )
+    }
+
+    /** Updates the icon drawable and redraws it */
+    fun redraw() {
+        drawable = composeDrawable(parentIcon.info, drawParams)
+        invalidate()
+    }
+
+    override fun dispatchDraw(canvas: Canvas) {
+        super.dispatchDraw(canvas)
+        drawable.draw(canvas)
     }
 }
diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
index 16b1854..e6654b1 100644
--- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
+++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
@@ -1,6 +1,7 @@
 package com.android.launcher3.backuprestore
 
 import android.content.Context
+import androidx.annotation.StringDef
 import com.android.launcher3.LauncherSettings.Favorites
 import com.android.launcher3.R
 import com.android.launcher3.util.ResourceBasedOverride
@@ -11,6 +12,39 @@
  */
 open class LauncherRestoreEventLogger : ResourceBasedOverride {
 
+    /** Enumeration of potential errors returned to calls of pause/resume app updates. */
+    @Retention(AnnotationRetention.SOURCE)
+    @StringDef(
+        RestoreError.PROFILE_DELETED,
+        RestoreError.MISSING_INFO,
+        RestoreError.MISSING_WIDGET_PROVIDER,
+        RestoreError.INVALID_LOCATION,
+        RestoreError.SHORTCUT_NOT_FOUND,
+        RestoreError.APP_NOT_INSTALLED,
+        RestoreError.WIDGETS_DISABLED,
+        RestoreError.PROFILE_NOT_RESTORED,
+        RestoreError.WIDGET_REMOVED,
+        RestoreError.GRID_MIGRATION_FAILURE,
+        RestoreError.NO_SEARCH_WIDGET,
+        RestoreError.INVALID_WIDGET_ID
+    )
+    annotation class RestoreError {
+        companion object {
+            const val PROFILE_DELETED = "user_profile_deleted"
+            const val MISSING_INFO = "missing_information_when_loading"
+            const val MISSING_WIDGET_PROVIDER = "missing_widget_provider"
+            const val INVALID_LOCATION = "invalid_size_or_location"
+            const val SHORTCUT_NOT_FOUND = "shortcut_not_found"
+            const val APP_NOT_INSTALLED = "app_not_installed"
+            const val WIDGETS_DISABLED = "widgets_disabled"
+            const val PROFILE_NOT_RESTORED = "profile_not_restored"
+            const val WIDGET_REMOVED = "widget_not_found"
+            const val GRID_MIGRATION_FAILURE = "grid_migration_failed"
+            const val NO_SEARCH_WIDGET = "no_search_widget"
+            const val INVALID_WIDGET_ID = "invalid_widget_id"
+        }
+    }
+
     companion object {
         const val TAG = "LauncherRestoreEventLogger"
 
@@ -54,12 +88,22 @@
     }
 
     /**
+     * Helper to log successfully restoring multiple items from the Favorites table.
+     *
+     * @param favoritesId The id of the item type from [Favorites] that was restored.
+     * @param count number of items that restored.
+     */
+    open fun logFavoritesItemsRestored(favoritesId: Int, count: Int) {
+        // no-op
+    }
+
+    /**
      * Helper to log a failure to restore a single item from the Favorites table.
      *
      * @param favoritesId The id of the item type from [Favorites] that was not restored.
      * @param error error type for why the data was not restored.
      */
-    open fun logSingleFavoritesItemRestoreFailed(favoritesId: Int, error: String?) {
+    open fun logSingleFavoritesItemRestoreFailed(favoritesId: Int, @RestoreError error: String?) {
         // no-op
     }
 
@@ -70,7 +114,11 @@
      * @param count number of items that failed to restore.
      * @param error error type for why the data was not restored.
      */
-    open fun logFavoritesItemsRestoreFailed(favoritesId: Int, count: Int, error: String?) {
+    open fun logFavoritesItemsRestoreFailed(
+        favoritesId: Int,
+        count: Int,
+        @RestoreError error: String?
+    ) {
         // no-op
     }
 
diff --git a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
index 8754b74..c303783 100644
--- a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
+++ b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
@@ -49,21 +49,37 @@
      * When changing the size of the widget this method will try first subtracting -1 in the x
      * dimension and then subtracting -1 in the y dimension until finding a possible solution or
      * until it no longer can reduce the span.
-     *
      * @param decX     whether it will decrease the horizontal or vertical span if it can't find a
      *                 solution for the current span.
      * @return the same solution variable
      */
     public ItemConfiguration findReorderSolution(ReorderParameters reorderParameters,
             boolean decX) {
+        return findReorderSolution(reorderParameters, mCellLayout.mDirectionVector, decX);
+    }
+
+    /**
+     * This method differs from closestEmptySpaceReorder and dropInPlaceSolution because this method
+     * will move items around and will change the shape of the item if possible to try to find a
+     * solution.
+     * <p>
+     * When changing the size of the widget this method will try first subtracting -1 in the x
+     * dimension and then subtracting -1 in the y dimension until finding a possible solution or
+     * until it no longer can reduce the span.
+     * @param direction Direction to attempt to push items if needed
+     * @param decX     whether it will decrease the horizontal or vertical span if it can't find a
+     *                 solution for the current span.
+     * @return the same solution variable
+     */
+    public ItemConfiguration findReorderSolution(ReorderParameters reorderParameters,
+            int[] direction, boolean decX) {
         return findReorderSolutionRecursive(reorderParameters.getPixelX(),
                 reorderParameters.getPixelY(), reorderParameters.getMinSpanX(),
                 reorderParameters.getMinSpanY(), reorderParameters.getSpanX(),
-                reorderParameters.getSpanY(), mCellLayout.mDirectionVector,
+                reorderParameters.getSpanY(), direction,
                 reorderParameters.getDragView(), decX, reorderParameters.getSolution());
     }
 
-
     private ItemConfiguration findReorderSolutionRecursive(int pixelX, int pixelY, int minSpanX,
             int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
             ItemConfiguration solution) {
diff --git a/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt b/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt
new file mode 100644
index 0000000..62b19d4
--- /dev/null
+++ b/src/com/android/launcher3/celllayout/ReorderPreviewAnimation.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.animation.ValueAnimator.areAnimatorsEnabled
+import android.util.ArrayMap
+import android.view.View
+import com.android.app.animation.Interpolators.DECELERATE_1_5
+import com.android.launcher3.CellLayout
+import com.android.launcher3.CellLayout.REORDER_ANIMATION_DURATION
+import com.android.launcher3.Reorderable
+import com.android.launcher3.Workspace
+import com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET
+import com.android.launcher3.util.Thunk
+import kotlin.math.abs
+import kotlin.math.atan
+import kotlin.math.cos
+import kotlin.math.sign
+import kotlin.math.sin
+
+/**
+ * Class which represents the reorder preview animations. These animations show that an item is in a
+ * temporary state, and hint at where the item will return to.
+ */
+class ReorderPreviewAnimation<T>(
+    val child: T,
+    // If the mode is MODE_HINT it will only move one period and stop, it then will be going
+    // backwards to the initial position, otherwise it will oscillate.
+    val mode: Int,
+    cellX0: Int,
+    cellY0: Int,
+    cellX1: Int,
+    cellY1: Int,
+    spanX: Int,
+    spanY: Int,
+    reorderMagnitude: Float,
+    cellLayout: CellLayout,
+    private val shakeAnimators: ArrayMap<Reorderable, ReorderPreviewAnimation<T>>
+) : ValueAnimator.AnimatorUpdateListener where T : View, T : Reorderable {
+
+    private var finalDeltaX = 0f
+    private var finalDeltaY = 0f
+    private var initDeltaX =
+        child.getTranslateDelegate().getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).value
+    private var initDeltaY =
+        child.getTranslateDelegate().getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).value
+    private var initScale = child.getReorderBounceScale()
+    private val finalScale = CellLayout.DEFAULT_SCALE - CHILD_DIVIDEND / child.width * initScale
+
+    private val dir = if (mode == MODE_HINT) -1 else 1
+    var animator: ValueAnimator =
+        ObjectAnimator.ofFloat(0f, 1f).also {
+            it.addUpdateListener(this)
+            it.setDuration((if (mode == MODE_HINT) HINT_DURATION else PREVIEW_DURATION).toLong())
+            it.startDelay = (Math.random() * 60).toLong()
+            // Animations are disabled in power save mode, causing the repeated animation to jump
+            // spastically between beginning and end states. Since this looks bad, we don't repeat
+            // the animation in power save mode.
+            if (areAnimatorsEnabled() && mode == MODE_PREVIEW) {
+                it.repeatCount = ValueAnimator.INFINITE
+                it.repeatMode = ValueAnimator.REVERSE
+            }
+        }
+
+    init {
+        val tmpRes = intArrayOf(0, 0)
+        cellLayout.regionToCenterPoint(cellX0, cellY0, spanX, spanY, tmpRes)
+        val (x0, y0) = tmpRes
+        cellLayout.regionToCenterPoint(cellX1, cellY1, spanX, spanY, tmpRes)
+        val (x1, y1) = tmpRes
+        val dX = x1 - x0
+        val dY = y1 - y0
+
+        if (dX != 0 || dY != 0) {
+            if (dY == 0) {
+                finalDeltaX = -dir * sign(dX.toFloat()) * reorderMagnitude
+            } else if (dX == 0) {
+                finalDeltaY = -dir * sign(dY.toFloat()) * reorderMagnitude
+            } else {
+                val angle = atan((dY.toFloat() / dX))
+                finalDeltaX = (-dir * sign(dX.toFloat()) * abs(cos(angle) * reorderMagnitude))
+                finalDeltaY = (-dir * sign(dY.toFloat()) * abs(sin(angle) * reorderMagnitude))
+            }
+        }
+    }
+
+    private fun setInitialAnimationValuesToBaseline() {
+        initScale = CellLayout.DEFAULT_SCALE
+        initDeltaX = 0f
+        initDeltaY = 0f
+    }
+
+    fun animate() {
+        val noMovement = finalDeltaX == 0f && finalDeltaY == 0f
+        if (shakeAnimators.containsKey(child)) {
+            val oldAnimation: ReorderPreviewAnimation<T>? = shakeAnimators.remove(child)
+            if (noMovement) {
+                // A previous animation for this item exists, and no new animation will exist.
+                // Finish the old animation smoothly.
+                oldAnimation!!.finishAnimation()
+                return
+            } else {
+                // A previous animation for this item exists, and a new one will exist. Stop
+                // the old animation in its tracks, and proceed with the new one.
+                oldAnimation!!.cancel()
+            }
+        }
+        if (noMovement) {
+            return
+        }
+        shakeAnimators[child] = this
+        animator.start()
+    }
+
+    override fun onAnimationUpdate(updatedAnimation: ValueAnimator) {
+        val progress = updatedAnimation.animatedValue as Float
+        child
+            .getTranslateDelegate()
+            .setTranslation(
+                INDEX_REORDER_BOUNCE_OFFSET,
+                /* x = */ progress * finalDeltaX + (1 - progress) * initDeltaX,
+                /* y = */ progress * finalDeltaY + (1 - progress) * initDeltaY
+            )
+        child.setReorderBounceScale(progress * finalScale + (1 - progress) * initScale)
+    }
+
+    private fun cancel() {
+        animator.cancel()
+    }
+
+    /** Smoothly returns the item to its baseline position / scale */
+    @Thunk
+    fun finishAnimation() {
+        animator.cancel()
+        setInitialAnimationValuesToBaseline()
+        animator = ObjectAnimator.ofFloat((animator.animatedValue as Float), 0f)
+        animator.addUpdateListener(this)
+        animator.interpolator = DECELERATE_1_5
+        animator.setDuration(REORDER_ANIMATION_DURATION.toLong())
+        animator.start()
+    }
+
+    companion object {
+        const val PREVIEW_DURATION = 300
+        const val HINT_DURATION = Workspace.REORDER_TIMEOUT
+        private const val CHILD_DIVIDEND = 4.0f
+        const val MODE_HINT = 0
+        const val MODE_PREVIEW = 1
+    }
+}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index d37b1f0..5f786a4 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -110,9 +110,6 @@
     }
 
     public static int getRecommendedTimeoutMillis(Context context, int originalTimeout, int flags) {
-        if (Utilities.ATLEAST_Q) {
-            return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags);
-        }
-        return originalTimeout;
+        return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags);
     }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e1816cb..3badc64 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -17,24 +17,17 @@
 package com.android.launcher3.config;
 
 import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
-import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
-import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
-import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
-import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
-import static com.android.launcher3.uioverrides.flags.FlagsFactory.getIntFlag;
-import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
+import static com.android.launcher3.config.FeatureFlags.BooleanFlag.DISABLED;
+import static com.android.launcher3.config.FeatureFlags.BooleanFlag.ENABLED;
 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
 
-import android.view.ViewConfiguration;
+import android.content.res.Resources;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.BuildConfig;
 import com.android.launcher3.Flags;
 
-import java.util.function.Predicate;
-import java.util.function.ToIntFunction;
-
 /**
  * Defines a set of flags used to control various launcher behaviors.
  * <p>
@@ -42,11 +35,6 @@
  */
 public final class FeatureFlags {
 
-    @VisibleForTesting
-    public static Predicate<BooleanFlag> sBooleanReader = f -> f.mCurrentValue;
-    @VisibleForTesting
-    public static ToIntFunction<IntFlag> sIntReader = f -> f.mCurrentValue;
-
     private FeatureFlags() { }
 
     /**
@@ -92,7 +80,6 @@
     public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476,
             "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED,
             "Show an 'Undo' snackbar when users dismiss a predicted hotseat item");
-
     public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171,
             "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame");
 
@@ -116,33 +103,13 @@
             getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
                     "Allow entering All Apps from Overview (e.g. long swipe up from app)");
 
-    public static final BooleanFlag CUSTOM_LPNH_THRESHOLDS =
-            getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
-                    "Add dev options to customize the LPNH trigger slop and milliseconds");
-
-    public static final BooleanFlag ANIMATE_LPNH =
-            getReleaseFlag(308693847, "ANIMATE_LPNH", TEAMFOOD,
-                    "Animates navbar when long pressing");
-
-    public static final BooleanFlag SHRINK_NAV_HANDLE_ON_PRESS =
-            getReleaseFlag(314158312, "SHRINK_NAV_HANDLE_ON_PRESS", DISABLED,
-                    "Shrinks navbar when long pressing if ANIMATE_LPNH is enabled");
-
-    public static final IntFlag LPNH_SLOP_PERCENTAGE =
-            getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
-                    "Controls touch slop percentage for lpnh");
-
-    public static final IntFlag LPNH_TIMEOUT_MS =
-            getIntFlag(301680992, "LPNH_TIMEOUT_MS", ViewConfiguration.getLongPressTimeout(),
-                    "Controls lpnh timeout in milliseconds");
-
     public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
             270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
             "Enable option to show keyboard when going to all-apps");
 
     // TODO(Block 5): Clean up flags
     public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
-            "ENABLE_TWOLINE_DEVICESEARCH", ENABLED,
+            "ENABLE_TWOLINE_DEVICESEARCH", DISABLED,
             "Enable two line label for icons with labels on device search.");
 
     public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
@@ -161,18 +128,9 @@
             "SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
             "Enable dragging and dropping to pin apps within secondary display");
 
-    // TODO(Block 7): Clean up flags
-    public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(270396209,
-            "ENABLE_FORCED_MONO_ICON", DISABLED,
-            "Enable the ability to generate monochromatic icons, if it is not provided by the app");
-
     // TODO(Block 8): Clean up flags
 
     // TODO(Block 9): Clean up flags
-    public static final BooleanFlag UNFOLDED_WIDGET_PICKER = getDebugFlag(301918659,
-            "UNFOLDED_WIDGET_PICKER", DISABLED, "Enable new widget picker that takes "
-                    + "advantage of the unfolded foldable format");
-
     public static final BooleanFlag MULTI_SELECT_EDIT_MODE = getDebugFlag(270709220,
             "MULTI_SELECT_EDIT_MODE", DISABLED, "Enable new multi-select edit mode "
                     + "for home screen");
@@ -188,11 +146,6 @@
             "ENABLE_SMARTSPACE_REMOVAL", DISABLED, "Enable SmartSpace removal for "
             + "home screen");
 
-    // TODO(Block 10): Clean up flags
-    public static final BooleanFlag ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION = getDebugFlag(270614790,
-            "ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED,
-            "Enables predictive back animation from all apps and widgets to home");
-
     // TODO(Block 11): Clean up flags
     public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274,
             "FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace");
@@ -201,10 +154,6 @@
             "ENABLE_PARAMETRIZE_REORDER", DISABLED,
             "Enables generating the reorder using a set of parameters");
 
-    public static final BooleanFlag ENABLE_NO_LONG_PRESS_DRAG = getDebugFlag(299748096,
-            "ENABLE_NO_LONG_PRESS_DRAG", ENABLED,
-            "Don't trigger the drag if we are still under long press");
-
     // TODO(Block 12): Clean up flags
     public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680,
             "ENABLE_MULTI_INSTANCE", DISABLED,
@@ -217,10 +166,22 @@
 
     // TODO(Block 14): Cleanup flags
     public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES",
-            TEAMFOOD, "Sends a notification whenever launcher encounters an uncaught exception.");
+            DISABLED, "Sends a notification whenever launcher encounters an uncaught exception.");
 
     public static final boolean ENABLE_TASKBAR_NAVBAR_UNIFICATION =
-            enableTaskbarNavbarUnification();
+            enableTaskbarNavbarUnification() && !isPhone();
+
+    private static boolean isPhone() {
+        final boolean isPhone;
+        int foldedDeviceStatesId = Resources.getSystem().getIdentifier(
+                "config_foldedDeviceStates", "array", "android");
+        if (foldedDeviceStatesId != 0) {
+            isPhone = Resources.getSystem().getIntArray(foldedDeviceStatesId).length == 0;
+        } else {
+            isPhone = true;
+        }
+        return isPhone;
+    }
 
     // Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
     public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
@@ -231,7 +192,7 @@
                 // Task bar pinning and task bar nav bar unification are both dependent on
                 // ENABLE_TASKBAR_NO_RECREATION. We want to turn ENABLE_TASKBAR_NO_RECREATION on
                 // when either of the dependent features is turned on.
-                || ENABLE_TASKBAR_PINNING.get() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
+                || enableTaskbarPinning() || ENABLE_TASKBAR_NAVBAR_UNIFICATION;
     }
 
     // TODO(Block 16): Clean up flags
@@ -259,10 +220,7 @@
 
     // Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS.
     public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
-            "ENABLE_TWOLINE_ALLAPPS", ENABLED, "Enables two line label inside all apps.");
-    public static boolean enableTwolineAllapps() {
-        return ENABLE_TWOLINE_ALLAPPS.get() || Flags.enableTwolineAllapps();
-    }
+            "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
 
     public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
             "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
@@ -275,46 +233,10 @@
             "INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED,
             "Inject fallback app corpus result when AiAi fails to return it.");
 
-    public static final BooleanFlag ENABLE_LONG_PRESS_NAV_HANDLE =
-            getReleaseFlag(299682306, "ENABLE_LONG_PRESS_NAV_HANDLE", TEAMFOOD,
-                    "Enables long pressing on the bottom bar nav handle to trigger events.");
-
-    public static final BooleanFlag ENABLE_SEARCH_HAPTIC_HINT =
-            getReleaseFlag(314005131, "ENABLE_SEARCH_HAPTIC_HINT", ENABLED,
-                    "Enables haptic hint while long pressing on the bottom bar nav handle.");
-
-    public static final BooleanFlag ENABLE_SEARCH_HAPTIC_COMMIT =
-            getReleaseFlag(314005577, "ENABLE_SEARCH_HAPTIC_COMMIT", ENABLED,
-                    "Enables haptic hint at end of long pressing on the bottom bar nav handle.");
-
-    public static final IntFlag LPNH_HAPTIC_HINT_START_SCALE_PERCENT =
-            getIntFlag(309972570, "LPNH_HAPTIC_HINT_START_SCALE_PERCENT", 0,
-            "Haptic hint start scale.");
-
-    public static final IntFlag LPNH_HAPTIC_HINT_END_SCALE_PERCENT =
-            getIntFlag(309972570, "LPNH_HAPTIC_HINT_END_SCALE_PERCENT", 100,
-            "Haptic hint end scale.");
-
-    public static final IntFlag LPNH_HAPTIC_HINT_SCALE_EXPONENT =
-            getIntFlag(309972570, "LPNH_HAPTIC_HINT_SCALE_EXPONENT", 1,
-            "Haptic hint scale exponent.");
-
-    public static final IntFlag LPNH_HAPTIC_HINT_ITERATIONS =
-            getIntFlag(309972570, "LPNH_HAPTIC_HINT_ITERATIONS", 50,
-            "Haptic hint number of iterations.");
-
-    public static final BooleanFlag ENABLE_LPNH_DEEP_PRESS =
-            getReleaseFlag(310952290, "ENABLE_LPNH_DEEP_PRESS", ENABLED,
-                    "Long press of nav handle is instantly triggered if deep press is detected.");
-
-    public static final IntFlag LPNH_HAPTIC_HINT_DELAY =
-            getIntFlag(309972570, "LPNH_HAPTIC_HINT_DELAY", 0,
-                    "Delay before haptic hint starts.");
-
     // TODO(Block 17): Clean up flags
     // Aconfig migration complete for ENABLE_TASKBAR_PINNING.
-    private static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(270396583,
-            "ENABLE_TASKBAR_PINNING", TEAMFOOD,
+    private static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(296231746,
+            "ENABLE_TASKBAR_PINNING", DISABLED,
             "Enables taskbar pinning to allow user to switch between transient and persistent "
                     + "taskbar flavors");
 
@@ -322,20 +244,6 @@
         return ENABLE_TASKBAR_PINNING.get() || Flags.enableTaskbarPinning();
     }
 
-    /**
-     * Use a static boolean to gate the taskbar pinning education step
-     */
-    public static boolean enableTaskbarPinningEdu() {
-        boolean enableTaskbarPinningEdu = false;
-        return enableTaskbarPinning() && enableTaskbarPinningEdu;
-    }
-
-    public static final BooleanFlag MOVE_STARTUP_DATA_TO_DEVICE_PROTECTED_STORAGE = getDebugFlag(
-            251502424, "ENABLE_BOOT_AWARE_STARTUP_DATA", DISABLED,
-            "Marks LauncherPref data as (and allows it to) available while the device is"
-                    + " locked. Enabling this causes a 1-time movement of certain SharedPreferences"
-                    + " data. Improves startup latency.");
-
     // Aconfig migration complete for ENABLE_APP_PAIRS.
     public static final BooleanFlag ENABLE_APP_PAIRS = getDebugFlag(274189428,
             "ENABLE_APP_PAIRS", DISABLED,
@@ -368,7 +276,7 @@
 
     // Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER.
     public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414,
-            "ENABLE_HOME_TRANSITION_LISTENER", TEAMFOOD,
+            "ENABLE_HOME_TRANSITION_LISTENER", DISABLED,
             "Enables launcher to listen to all transitions that include home activity.");
 
     public static boolean enableHomeTransitionListener() {
@@ -390,15 +298,6 @@
                     + "waiting for SystemUI and then merging the SystemUI progress whenever we "
                     + "start receiving the events");
 
-    // TODO(Block 24): Clean up flags
-    public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
-            "ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
-            "Enable the new grid migration logic, keeping pages when src < dest");
-
-    public static final BooleanFlag ENABLE_CACHED_WIDGET = getDebugFlag(270395008,
-            "ENABLE_CACHED_WIDGET", ENABLED,
-            "Show previously cached widgets as opposed to deferred widget where available");
-
     // TODO(Block 25): Clean up flags
     public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
             "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
@@ -433,10 +332,6 @@
             "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED,
             "Enforce rounded corners on all App Widgets");
 
-    public static final BooleanFlag ENABLE_ICON_LABEL_AUTO_SCALING = getDebugFlag(270393294,
-            "ENABLE_ICON_LABEL_AUTO_SCALING", ENABLED,
-            "Enables scaling/spacing for icon labels to make more characters visible");
-
     public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973,
             "USE_LOCAL_ICON_OVERRIDES", ENABLED,
             "Use inbuilt monochrome icons if app doesn't provide one");
@@ -476,7 +371,7 @@
     // Aconfig migration complete for ENABLE_RESPONSIVE_WORKSPACE.
     @VisibleForTesting
     public static final BooleanFlag ENABLE_RESPONSIVE_WORKSPACE = getDebugFlag(241386436,
-            "ENABLE_RESPONSIVE_WORKSPACE", TEAMFOOD,
+            "ENABLE_RESPONSIVE_WORKSPACE", DISABLED,
             "Enables new workspace grid calculations method.");
     public static boolean enableResponsiveWorkspace() {
         return ENABLE_RESPONSIVE_WORKSPACE.get() || Flags.enableResponsiveWorkspace();
@@ -484,57 +379,37 @@
 
     // TODO(Block 33): Clean up flags
     public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
-            "ENABLE_ALL_APPS_RV_PREINFLATION", TEAMFOOD,
+            "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
             "Enables preinflating all apps icons to avoid scrolling jank.");
     public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
-            "ALL_APPS_GONE_VISIBILITY", TEAMFOOD,
+            "ALL_APPS_GONE_VISIBILITY", ENABLED,
             "Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
 
-    // TODO(Block 34): Empty block
-    // Please only add flags to your assigned block. If you do not have a block:
-    // 1. Assign yourself this block
-    // 2. Add your flag to this block
-    // 3. Add a new empty block below this one
-    // 4. Move this comment to that new empty block
-    // This is all to prevent merge conflicts in the future and help keep track of who owns which
-    // flags.
-    // List of assigned blocks can be found: http://go/gnl-flags-block-directory
-
-    public static class BooleanFlag {
-
-        private final boolean mCurrentValue;
-
-        public BooleanFlag(boolean currentValue) {
-            mCurrentValue = currentValue;
-        }
-
-        public boolean get() {
-            return sBooleanReader.test(this);
-        }
+    public static BooleanFlag getDebugFlag(
+            int bugId, String key, BooleanFlag flagState, String description) {
+        return flagState;
     }
 
-    /**
-     * Class representing an integer flag
-     */
-    public static class IntFlag {
-
-        private final int mCurrentValue;
-
-        public IntFlag(int currentValue) {
-            mCurrentValue = currentValue;
-        }
-
-        public int get() {
-            return sIntReader.applyAsInt(this);
-        }
+    public static BooleanFlag getReleaseFlag(
+            int bugId, String key, BooleanFlag flagState, String description) {
+        return flagState;
     }
 
     /**
      * Enabled state for a flag
      */
-    public enum FlagState {
-        ENABLED,
-        DISABLED,
-        TEAMFOOD    // Enabled in team food
+    public enum BooleanFlag {
+        ENABLED(true),
+        DISABLED(false);
+
+        private final boolean mValue;
+
+        BooleanFlag(boolean value) {
+            mValue = value;
+        }
+
+        public boolean get() {
+            return mValue;
+        }
     }
 }
diff --git a/src/com/android/launcher3/dot/DotInfo.java b/src/com/android/launcher3/dot/DotInfo.java
index fc180d1..64864b0 100644
--- a/src/com/android/launcher3/dot/DotInfo.java
+++ b/src/com/android/launcher3/dot/DotInfo.java
@@ -18,7 +18,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.notification.NotificationInfo;
 import com.android.launcher3.notification.NotificationKeyData;
 
 import java.util.ArrayList;
@@ -32,8 +31,7 @@
     public static final int MAX_COUNT = 999;
 
     /**
-     * The keys of the notifications that this dot represents. These keys can later be
-     * used to retrieve {@link NotificationInfo}'s.
+     * The keys of the notifications that this dot represents.
      */
     private final List<NotificationKeyData> mNotificationKeys = new ArrayList<>();
 
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 213c458..ec0a222 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -67,7 +67,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.pm.PinRequestHelper;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.views.AbstractSlideInView;
@@ -162,7 +162,7 @@
             finish();
             return;
         }
-        ApplicationInfo info = new PackageManagerHelper(this)
+        ApplicationInfo info = PackageManagerHelper.INSTANCE.get(this)
                 .getApplicationInfo(targetApp.packageName, targetApp.user, 0);
         if (info == null) {
             finish();
@@ -258,8 +258,9 @@
                         .addCategory(Intent.CATEGORY_HOME)
                         .setPackage(getPackageName())
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        Launcher.ACTIVITY_TRACKER.registerCallback(listener);
-        startActivity(homeIntent, ApiWrapper.createFadeOutAnimOptions(this).toBundle());
+        Launcher.ACTIVITY_TRACKER.registerCallback(listener, "AddItemActivity.onLongClick");
+        startActivity(homeIntent,
+                ApiWrapper.INSTANCE.get(this).createFadeOutAnimOptions().toBundle());
         logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED);
         mFinishOnPause = true;
         return false;
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 777f4d5..bc5a164 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,8 +16,7 @@
 
 package com.android.launcher3.dragndrop;
 
-import static com.android.launcher3.Utilities.ATLEAST_Q;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_NO_LONG_PRESS_DRAG;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -32,8 +31,11 @@
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
+import com.android.launcher3.Flags;
 import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.ActivityContext;
@@ -224,6 +226,12 @@
         }
     }
 
+    protected boolean isItemPinnable() {
+        return !Flags.privateSpaceRestrictItemDrag()
+                || !(mDragObject.dragInfo instanceof ItemInfoWithIcon itemInfoWithIcon)
+                || (itemInfoWithIcon.runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0;
+    }
+
     public Optional<InstanceId> getLogInstanceId() {
         return Optional.ofNullable(mDragObject)
                 .map(dragObject -> dragObject.logInstanceId);
@@ -282,7 +290,8 @@
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
             ItemInfo dragInfo = mDragObject.dragInfo;
-            if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
+            if ((dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo))
+                    || (dragInfo instanceof AppPairInfo api && api.anyMatch(matcher))) {
                 cancelDrag();
             }
         }
@@ -405,9 +414,7 @@
             mMotionDown.set(dragLayerPos.x,  dragLayerPos.y);
         }
 
-        if (ATLEAST_Q) {
-            mLastTouchClassification = ev.getClassification();
-        }
+        mLastTouchClassification = ev.getClassification();
         return mDragDriver != null && mDragDriver.onInterceptTouchEvent(ev);
     }
 
@@ -442,7 +449,7 @@
         mLastTouch.set(x, y);
 
         int distanceDragged = mDistanceSinceScroll;
-        if (ATLEAST_Q && mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
+        if (mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
             distanceDragged /= DEEP_PRESS_DISTANCE_FACTOR;
         }
         if (mIsInPreDrag && mOptions.preDragCondition != null
@@ -464,7 +471,7 @@
 
     private DropTarget checkTouchMove(final int x, final int y) {
         // If we are in predrag, don't trigger any other event until we get out of it
-        if (ENABLE_NO_LONG_PRESS_DRAG.get() && mIsInPreDrag) {
+        if (mIsInPreDrag) {
             return mLastDropTarget;
         }
         DropTarget dropTarget = findDropTarget(x, y);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index f18f900..db693f0 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -42,6 +42,8 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.Nullable;
+
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DropTargetBar;
@@ -388,7 +390,13 @@
         mDropAnim.start();
     }
 
-    public void clearAnimatedView() {
+    /**
+     * Remove the drop view and end the drag animation.
+     *
+     * @return {@link DragView} that is removed.
+     */
+    @Nullable
+    public DragView clearAnimatedView() {
         if (mDropAnim != null) {
             mDropAnim.cancel();
         }
@@ -396,8 +404,10 @@
         if (mDropView != null) {
             mDragController.onDeferredEndDrag(mDropView);
         }
+        DragView ret = mDropView;
         mDropView = null;
         invalidate();
+        return ret;
     }
 
     public View getAnimatedView() {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1f07352..bcee442 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -30,6 +30,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.TargetApi;
+import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -563,6 +564,11 @@
         return mContentViewParent;
     }
 
+    /** Return true if {@link mContent} is a {@link AppWidgetHostView}. */
+    public boolean containsAppWidgetHostView() {
+        return mContent instanceof AppWidgetHostView;
+    }
+
     private static class SpringFloatValue {
 
         private static final FloatPropertyCompat<SpringFloatValue> VALUE =
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 6f295e6..6a43b24 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -37,7 +37,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.PreviewBackground;
 import com.android.launcher3.icons.BitmapRenderer;
@@ -74,13 +73,9 @@
         return mBadge;
     }
 
-    @TargetApi(Build.VERSION_CODES.P)
     public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
             ActivityContext activity, int folderId, Point size) {
         Preconditions.assertNonUiThread();
-        if (!Utilities.ATLEAST_P) {
-            return null;
-        }
 
         // assume square
         if (size.x != size.y) {
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index da6f446..f3708a2 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -149,9 +149,10 @@
 
         handleMoveEvent(mLastTouch.x, mLastTouch.y);
 
-        if (!mActivity.isTouchInProgress() && options.simulatedDndStartPoint == null) {
+        if (!isItemPinnable()
+                || (!mActivity.isTouchInProgress() && options.simulatedDndStartPoint == null)) {
             // If it is an internal drag and the touch is already complete, cancel immediately
-            MAIN_EXECUTOR.submit(this::cancelDrag);
+            MAIN_EXECUTOR.post(this::cancelDrag);
         }
         return dragView;
     }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 084f829..dcc55e6 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -19,6 +19,9 @@
 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;
@@ -40,6 +43,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
+import android.os.Looper;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.TextUtils;
@@ -65,14 +69,12 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Alarm;
-import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.OnAlarmListener;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
@@ -165,10 +167,26 @@
     private static final Rect sTempRect = new Rect();
     private static final int MIN_FOLDERS_FOR_HARDWARE_OPTIMIZATION = 10;
 
-    private final Alarm mReorderAlarm = new Alarm();
-    private final Alarm mOnExitAlarm = new Alarm();
-    private final Alarm mOnScrollHintAlarm = new Alarm();
-    final Alarm mScrollPauseAlarm = new Alarm();
+    /**
+     * Checks if {@code o} is an {@link ItemInfo} type that can be placed in folders.
+     */
+    public static boolean willAccept(Object o) {
+        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 final Alarm mReorderAlarm = new Alarm(Looper.getMainLooper());
+    private final Alarm mOnExitAlarm = new Alarm(Looper.getMainLooper());
+    private final Alarm mOnScrollHintAlarm = new Alarm(Looper.getMainLooper());
+    final Alarm mScrollPauseAlarm = new Alarm(Looper.getMainLooper());
 
     final ArrayList<View> mItemsInReadingOrder = new ArrayList<View>();
 
@@ -283,6 +301,8 @@
         mContent.setFolder(this);
 
         mPageIndicator = findViewById(R.id.folder_page_indicator);
+        mFooter = findViewById(R.id.folder_footer);
+        mFooterHeight = dp.folderFooterHeightPx;
         mFolderName = findViewById(R.id.folder_name);
         mFolderName.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp.folderLabelTextSizePx);
         mFolderName.setOnBackKeyListener(this);
@@ -293,14 +313,13 @@
                 | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
         mFolderName.forceDisableSuggestions(true);
+        mFolderName.setPadding(mFolderName.getPaddingLeft(),
+                (mFooterHeight - mFolderName.getLineHeight()) / 2,
+                mFolderName.getPaddingRight(),
+                (mFooterHeight - mFolderName.getLineHeight()) / 2);
 
-        mFooter = findViewById(R.id.folder_footer);
-        mFooterHeight = dp.folderFooterHeightPx;
-
-        if (Utilities.ATLEAST_R) {
-            mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
-            setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
-        }
+        mKeyboardInsetAnimationCallback = new KeyboardInsetAnimationCallback(this);
+        setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
     }
 
     public boolean onLongClick(View v) {
@@ -311,9 +330,7 @@
 
     public boolean startDrag(View v, DragOptions options) {
         Object tag = v.getTag();
-        if (tag instanceof WorkspaceItemInfo) {
-            WorkspaceItemInfo item = (WorkspaceItemInfo) tag;
-
+        if (tag instanceof ItemInfo item) {
             mEmptyCellRank = item.rank;
             mCurrentDragView = v;
 
@@ -322,8 +339,9 @@
                 mDragController.addDragListener(new AccessibleDragListenerAdapter(
                         mContent, FolderAccessibilityHelper::new) {
                     @Override
-                    protected void enableAccessibleDrag(boolean enable) {
-                        super.enableAccessibleDrag(enable);
+                    protected void enableAccessibleDrag(boolean enable,
+                            @Nullable DragObject dragObject) {
+                        super.enableAccessibleDrag(enable, dragObject);
                         mFooter.setImportantForAccessibility(enable
                                 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
                                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
@@ -343,14 +361,12 @@
         }
 
         mContent.removeItem(mCurrentDragView);
-        if (dragObject.dragInfo instanceof WorkspaceItemInfo) {
-            mItemsInvalidated = true;
+        mItemsInvalidated = true;
 
-            // 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((WorkspaceItemInfo) dragObject.dragInfo, true);
-            }
+        // 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);
         }
         mDragInProgress = true;
         mItemAddedBackToSelfViaIcon = false;
@@ -422,18 +438,16 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
-        if (Utilities.ATLEAST_R) {
-            this.setTranslationY(0);
+        this.setTranslationY(0);
 
-            if (windowInsets.isVisible(WindowInsets.Type.ime())) {
-                Insets keyboardInsets = windowInsets.getInsets(WindowInsets.Type.ime());
-                int folderHeightFromBottom = getHeightFromBottom();
+        if (windowInsets.isVisible(WindowInsets.Type.ime())) {
+            Insets keyboardInsets = windowInsets.getInsets(WindowInsets.Type.ime());
+            int folderHeightFromBottom = getHeightFromBottom();
 
-                if (keyboardInsets.bottom > folderHeightFromBottom) {
-                    // Translate this folder above the keyboard, then add the folder name's padding
-                    this.setTranslationY(folderHeightFromBottom - keyboardInsets.bottom
-                            - mFolderName.getPaddingBottom());
-                }
+            if (keyboardInsets.bottom > folderHeightFromBottom) {
+                // Translate this folder above the keyboard, then add the folder name's padding
+                this.setTranslationY(folderHeightFromBottom - keyboardInsets.bottom
+                        - mFolderName.getPaddingBottom());
             }
         }
 
@@ -492,7 +506,7 @@
         mInfo = info;
         mFromTitle = info.title;
         mFromLabelState = info.getFromLabelState();
-        ArrayList<WorkspaceItemInfo> children = info.contents;
+        ArrayList<ItemInfo> children = info.getContents();
         Collections.sort(children, ITEM_POS_COMPARATOR);
         updateItemLocationsInDatabaseBatch(true);
 
@@ -625,7 +639,7 @@
         // onDropComplete. Perform cleanup once drag-n-drop ends.
         mDragController.addDragListener(this);
 
-        ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.contents);
+        ArrayList<ItemInfo> items = new ArrayList<>(mInfo.getContents());
         mEmptyCellRank = items.size();
         items.add(null);    // Add an empty spot at the end
 
@@ -638,7 +652,7 @@
      * is played.
      */
     public void animateOpen() {
-        animateOpen(mInfo.contents, 0);
+        animateOpen(mInfo.getContents(), 0);
     }
 
     /**
@@ -646,7 +660,7 @@
      * is animated relative to the specified View. If the View is null, no animation
      * is played.
      */
-    private void animateOpen(List<WorkspaceItemInfo> items, int pageNo) {
+    private void animateOpen(List<ItemInfo> items, int pageNo) {
         if (items == null || items.size() <= 1) {
             Log.d(TAG, "Couldn't animate folder open because items is: " + items);
             return;
@@ -804,6 +818,14 @@
             return;
         }
 
+        int size = getIconsInReadingOrder().size();
+        if (size <= 1) {
+            Log.d(TAG, "Couldn't animate folder closed because there's " + size + " icons");
+            closeComplete(false);
+            post(this::announceAccessibilityChanges);
+            return;
+        }
+
         mContent.completePendingPageChanges();
         mContent.snapToPageImmediately(mContent.getDestinationPage());
 
@@ -812,15 +834,13 @@
         a.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
-                if (Utilities.ATLEAST_R) {
-                    setWindowInsetsAnimationCallback(null);
-                }
+                setWindowInsetsAnimationCallback(null);
                 mIsAnimatingClosed = true;
             }
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                if (Utilities.ATLEAST_R && mKeyboardInsetAnimationCallback != null) {
+                if (mKeyboardInsetAnimationCallback != null) {
                     setWindowInsetsAnimationCallback(mKeyboardInsetAnimationCallback);
                 }
                 closeComplete(true);
@@ -889,8 +909,7 @@
     public boolean acceptDrop(DragObject d) {
         final ItemInfo item = d.dragInfo;
         final int itemType = item.itemType;
-        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT));
+        return Folder.willAcceptItemType(itemType);
     }
 
     public void onDragEnter(DragObject d) {
@@ -1035,12 +1054,15 @@
     public void onDropCompleted(final View target, final DragObject d,
             final boolean success) {
         if (success) {
+            if (getItemCount() <= 1) {
+                mDeleteFolderOnDropCompleted = true;
+            }
             if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon && target != this) {
                 replaceFolderWithFinalItem();
             }
         } else {
             // The drag failed, we need to return the item to the folder
-            WorkspaceItemInfo info = (WorkspaceItemInfo) d.dragInfo;
+            ItemInfo info = d.dragInfo;
             View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
                     ? mCurrentDragView : mContent.createNewView(info);
             ArrayList<View> views = getIconsInReadingOrder();
@@ -1087,9 +1109,9 @@
                 mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
 
         ArrayList<ItemInfo> items = new ArrayList<>();
-        int total = mInfo.contents.size();
+        int total = mInfo.getContents().size();
         for (int i = 0; i < total; i++) {
-            WorkspaceItemInfo itemInfo = mInfo.contents.get(i);
+            ItemInfo itemInfo = mInfo.getContents().get(i);
             if (verifier.updateRankAndPos(itemInfo, i)) {
                 items.add(itemInfo);
             }
@@ -1102,8 +1124,7 @@
             Executors.MODEL_EXECUTOR.post(() -> {
                 FolderNameInfos nameInfos = new FolderNameInfos();
                 FolderNameProvider fnp = FolderNameProvider.newInstance(getContext());
-                fnp.getSuggestedFolderName(
-                        getContext(), mInfo.contents, nameInfos);
+                fnp.getSuggestedFolderName(getContext(), mInfo.getAppContents(), nameInfos);
                 mInfo.suggestedFolderNames = nameInfos;
             });
         }
@@ -1207,7 +1228,7 @@
     }
 
     public int getItemCount() {
-        return mInfo.contents.size();
+        return mInfo.getContents().size();
     }
 
     void replaceFolderWithFinalItem() {
@@ -1288,15 +1309,15 @@
             d.deferDragViewCleanupPostAnimation = false;
             mRearrangeOnClose = true;
         } else {
-            final WorkspaceItemInfo si;
+            final ItemInfo si;
             if (pasiSi != null) {
                 si = pasiSi;
             } else if (d.dragInfo instanceof WorkspaceItemFactory) {
                 // Came from all apps -- make a copy.
                 si = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(launcher);
             } else {
-                // WorkspaceItemInfo
-                si = (WorkspaceItemInfo) d.dragInfo;
+                // WorkspaceItemInfo or AppPairInfo
+                si = d.dragInfo;
             }
 
             View currentDragView;
@@ -1304,7 +1325,7 @@
                 currentDragView = mContent.createAndAddViewForRank(si, mEmptyCellRank);
 
                 // Actually move the item in the database if it was an external drag. Call this
-                // before creating the view, so that WorkspaceItemInfo is updated appropriately.
+                // before creating the view, so that the ItemInfo is updated appropriately.
                 mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(
                         si, mInfo.id, 0, si.cellX, si.cellY);
                 mIsExternalDrag = false;
@@ -1366,14 +1387,14 @@
     // This is used so the item doesn't immediately appear in the folder when added. In one case
     // we need to create the illusion that the item isn't added back to the folder yet, to
     // to correspond to the animation of the icon back into the folder. This is
-    public void hideItem(WorkspaceItemInfo info) {
+    public void hideItem(ItemInfo info) {
         View v = getViewForInfo(info);
         if (v != null) {
             v.setVisibility(INVISIBLE);
         }
     }
 
-    public void showItem(WorkspaceItemInfo info) {
+    public void showItem(ItemInfo info) {
         View v = getViewForInfo(info);
         if (v != null) {
             v.setVisibility(VISIBLE);
@@ -1381,7 +1402,7 @@
     }
 
     @Override
-    public void onAdd(WorkspaceItemInfo item, int rank) {
+    public void onAdd(ItemInfo item, int rank) {
         FolderGridOrganizer verifier = new FolderGridOrganizer(
                 mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
         verifier.updateRankAndPos(item, rank);
@@ -1396,7 +1417,7 @@
     }
 
     @Override
-    public void onRemove(List<WorkspaceItemInfo> items) {
+    public void onRemove(List<ItemInfo> items) {
         mItemsInvalidated = true;
         items.stream().map(this::getViewForInfo).forEach(mContent::removeItem);
         if (mState == STATE_ANIMATING) {
@@ -1413,7 +1434,7 @@
         }
     }
 
-    private View getViewForInfo(final WorkspaceItemInfo item) {
+    private View getViewForInfo(final ItemInfo item) {
         return mContent.iterateOverItems((info, view) -> info == item);
     }
 
@@ -1422,6 +1443,11 @@
         updateTextViewFocus();
     }
 
+    @Override
+    public void onTitleChanged(CharSequence title) {
+        mFolderName.setText(title);
+    }
+
     /**
      * Utility methods to iterate over items of the view
      */
@@ -1441,7 +1467,7 @@
         return mItemsInReadingOrder;
     }
 
-    public List<BubbleTextView> getItemsOnPage(int page) {
+    public List<View> getItemsOnPage(int page) {
         ArrayList<View> allItems = getIconsInReadingOrder();
         int lastPage = mContent.getPageCount() - 1;
         int totalItemsInFolder = allItems.size();
@@ -1453,9 +1479,9 @@
         int startIndex = page * itemsPerPage;
         int endIndex = Math.min(startIndex + numItemsOnCurrentPage, allItems.size());
 
-        List<BubbleTextView> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
+        List<View> itemsOnCurrentPage = new ArrayList<>(numItemsOnCurrentPage);
         for (int i = startIndex; i < endIndex; ++i) {
-            itemsOnCurrentPage.add((BubbleTextView) allItems.get(i));
+            itemsOnCurrentPage.add(allItems.get(i));
         }
         return itemsOnCurrentPage;
     }
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index a91373b..7a2ec97 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -43,6 +43,7 @@
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PropertyResetListener;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.BaseDragLayer;
@@ -127,7 +128,7 @@
                 (BaseDragLayer.LayoutParams) mFolder.getLayoutParams();
         mFolderIcon.getPreviewItemManager().recomputePreviewDrawingParams();
         ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule();
-        final List<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(0);
+        final List<View> itemsInPreview = getPreviewIconsOnPage(0);
 
         // Match position of the FolderIcon
         final Rect folderIconPos = new Rect();
@@ -139,8 +140,8 @@
         // Match size/scale of icons in the preview
         float previewScale = rule.scaleForItem(itemsInPreview.size());
         float previewSize = rule.getIconSize() * previewScale;
-        float initialScale = previewSize / itemsInPreview.get(0).getIconSize()
-                * scaleRelativeToDragLayer;
+        float baseIconSize = getBubbleTextView(itemsInPreview.get(0)).getIconSize();
+        float initialScale = previewSize / baseIconSize * scaleRelativeToDragLayer;
         final float finalScale = 1f;
         float scale = mIsOpening ? initialScale : finalScale;
         mFolder.setPivotX(0);
@@ -198,11 +199,12 @@
         // Initialize the Folder items' text.
         PropertyResetListener colorResetListener =
                 new PropertyResetListener<>(TEXT_ALPHA_PROPERTY, 1f);
-        for (BubbleTextView icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
+        for (View icon : mFolder.getItemsOnPage(mFolder.mContent.getCurrentPage())) {
+            BubbleTextView titleText = getBubbleTextView(icon);
             if (mIsOpening) {
-                icon.setTextVisibility(false);
+                titleText.setTextVisibility(false);
             }
-            ObjectAnimator anim = icon.createTextAlphaAnimator(mIsOpening);
+            ObjectAnimator anim = titleText.createTextAlphaAnimator(mIsOpening);
             anim.addListener(colorResetListener);
             play(a, anim);
         }
@@ -339,7 +341,7 @@
     /**
      * Returns the list of "preview items" on {@param page}.
      */
-    private List<BubbleTextView> getPreviewIconsOnPage(int page) {
+    private List<View> getPreviewIconsOnPage(int page) {
         return mPreviewVerifier.setFolderInfo(mFolder.mInfo)
                 .previewItemsForPage(page, mFolder.getIconsInReadingOrder());
     }
@@ -351,7 +353,7 @@
             int previewItemOffsetX, int previewItemOffsetY) {
         ClippedFolderIconLayoutRule rule = mFolderIcon.getLayoutRule();
         boolean isOnFirstPage = mFolder.mContent.getCurrentPage() == 0;
-        final List<BubbleTextView> itemsInPreview = getPreviewIconsOnPage(
+        final List<View> itemsInPreview = getPreviewIconsOnPage(
                 isOnFirstPage ? 0 : mFolder.mContent.getCurrentPage());
         final int numItemsInPreview = itemsInPreview.size();
         final int numItemsInFirstPagePreview = isOnFirstPage
@@ -361,48 +363,49 @@
 
         ShortcutAndWidgetContainer cwc = mContent.getPageAt(0).getShortcutsAndWidgets();
         for (int i = 0; i < numItemsInPreview; ++i) {
-            final BubbleTextView btv = itemsInPreview.get(i);
-            CellLayoutLayoutParams btvLp = (CellLayoutLayoutParams) btv.getLayoutParams();
+            final View v = itemsInPreview.get(i);
+            CellLayoutLayoutParams vLp = (CellLayoutLayoutParams) v.getLayoutParams();
 
             // Calculate the final values in the LayoutParams.
-            btvLp.isLockedToGrid = true;
-            cwc.setupLp(btv);
+            vLp.isLockedToGrid = true;
+            cwc.setupLp(v);
 
             // Match scale of icons in the preview of the items on the first page.
             float previewScale = rule.scaleForItem(numItemsInFirstPagePreview);
             float previewSize = rule.getIconSize() * previewScale;
-            float iconScale = previewSize / itemsInPreview.get(i).getIconSize();
+            float baseIconSize = getBubbleTextView(v).getIconSize();
+            float iconScale = previewSize / baseIconSize;
 
             final float initialScale = iconScale / folderScale;
             final float finalScale = 1f;
             float scale = mIsOpening ? initialScale : finalScale;
-            btv.setScaleX(scale);
-            btv.setScaleY(scale);
+            v.setScaleX(scale);
+            v.setScaleY(scale);
 
             // Match positions of the icons in the folder with their positions in the preview
             rule.computePreviewItemDrawingParams(i, numItemsInFirstPagePreview, mTmpParams);
             // The PreviewLayoutRule assumes that the icon size takes up the entire width so we
             // offset by the actual size.
-            int iconOffsetX = (int) ((btvLp.width - btv.getIconSize()) * iconScale) / 2;
+            int iconOffsetX = (int) ((vLp.width - baseIconSize) * iconScale) / 2;
 
             final int previewPosX =
                     (int) ((mTmpParams.transX - iconOffsetX + previewItemOffsetX) / folderScale);
-            final float paddingTop = btv.getPaddingTop() * iconScale;
+            final float paddingTop = v.getPaddingTop() * iconScale;
             final int previewPosY = (int) ((mTmpParams.transY + previewItemOffsetY - paddingTop)
                     / folderScale);
 
-            final float xDistance = previewPosX - btvLp.x;
-            final float yDistance = previewPosY - btvLp.y;
+            final float xDistance = previewPosX - vLp.x;
+            final float yDistance = previewPosY - vLp.y;
 
-            Animator translationX = getAnimator(btv, View.TRANSLATION_X, xDistance, 0f);
+            Animator translationX = getAnimator(v, View.TRANSLATION_X, xDistance, 0f);
             translationX.setInterpolator(previewItemInterpolator);
             play(animatorSet, translationX);
 
-            Animator translationY = getAnimator(btv, View.TRANSLATION_Y, yDistance, 0f);
+            Animator translationY = getAnimator(v, View.TRANSLATION_Y, yDistance, 0f);
             translationY.setInterpolator(previewItemInterpolator);
             play(animatorSet, translationY);
 
-            Animator scaleAnimator = getAnimator(btv, SCALE_PROPERTY, initialScale, finalScale);
+            Animator scaleAnimator = getAnimator(v, SCALE_PROPERTY, initialScale, finalScale);
             scaleAnimator.setInterpolator(previewItemInterpolator);
             play(animatorSet, scaleAnimator);
 
@@ -426,20 +429,20 @@
                     super.onAnimationStart(animation);
                     // Necessary to initialize values here because of the start delay.
                     if (mIsOpening) {
-                        btv.setTranslationX(xDistance);
-                        btv.setTranslationY(yDistance);
-                        btv.setScaleX(initialScale);
-                        btv.setScaleY(initialScale);
+                        v.setTranslationX(xDistance);
+                        v.setTranslationY(yDistance);
+                        v.setScaleX(initialScale);
+                        v.setScaleY(initialScale);
                     }
                 }
 
                 @Override
                 public void onAnimationEnd(Animator animation) {
                     super.onAnimationEnd(animation);
-                    btv.setTranslationX(0.0f);
-                    btv.setTranslationY(0.0f);
-                    btv.setScaleX(1f);
-                    btv.setScaleY(1f);
+                    v.setTranslationX(0.0f);
+                    v.setTranslationY(0.0f);
+                    v.setScaleX(1f);
+                    v.setScaleY(1f);
                 }
             });
         }
@@ -482,4 +485,15 @@
                 ? ObjectAnimator.ofArgb(drawable, property, v1, v2)
                 : ObjectAnimator.ofArgb(drawable, property, v2, v1);
     }
+
+    /**
+     * Gets the {@link com.android.launcher3.BubbleTextView} from an icon. In some cases the
+     * BubbleTextView is the whole icon itself, while in others it is contained within the view and
+     * only serves to store the title text.
+     */
+    private BubbleTextView getBubbleTextView(View v) {
+        return v instanceof AppPairIcon
+                ? ((AppPairIcon) v).getTitleTextView()
+                : (BubbleTextView) v;
+    }
 }
diff --git a/src/com/android/launcher3/folder/FolderGridOrganizer.java b/src/com/android/launcher3/folder/FolderGridOrganizer.java
index cc24761..593673d 100644
--- a/src/com/android/launcher3/folder/FolderGridOrganizer.java
+++ b/src/com/android/launcher3/folder/FolderGridOrganizer.java
@@ -57,7 +57,7 @@
      * Updates the organizer with the provided folder info
      */
     public FolderGridOrganizer setFolderInfo(FolderInfo info) {
-        return setContentSize(info.contents.size());
+        return setContentSize(info.getContents().size());
     }
 
     /**
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index f058ae4..4d88b68 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -29,8 +29,10 @@
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Property;
 import android.view.LayoutInflater;
@@ -69,6 +71,7 @@
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.logging.InstanceId;
 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;
@@ -116,11 +119,11 @@
     ClippedFolderIconLayoutRule mPreviewLayoutRule;
     private PreviewItemManager mPreviewItemManager;
     private PreviewItemDrawingParams mTmpParams = new PreviewItemDrawingParams(0, 0, 0);
-    private List<WorkspaceItemInfo> mCurrentPreviewItems = new ArrayList<>();
+    private List<ItemInfo> mCurrentPreviewItems = new ArrayList<>();
 
     boolean mAnimating = false;
 
-    private Alarm mOpenAlarm = new Alarm();
+    private Alarm mOpenAlarm = new Alarm(Looper.getMainLooper());
 
     private boolean mForceHideDot;
     @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
@@ -213,7 +216,7 @@
 
         // Keep the notification dot up to date with the sum of all the content's dots.
         FolderDotInfo folderDotInfo = new FolderDotInfo();
-        for (WorkspaceItemInfo si : folderInfo.contents) {
+        for (ItemInfo si : folderInfo.getContents()) {
             folderDotInfo.addDotInfo(activity.getDotInfoForItem(si));
         }
         icon.setDotInfo(folderDotInfo);
@@ -259,20 +262,18 @@
 
     private boolean willAcceptItem(ItemInfo item) {
         final int itemType = item.itemType;
-        return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) &&
-                item != mInfo && !mFolder.isOpen());
+        return (Folder.willAcceptItemType(itemType) && item != mInfo && !mFolder.isOpen());
     }
 
     public boolean acceptDrop(ItemInfo dragInfo) {
         return !mFolder.isDestroyed() && willAcceptItem(dragInfo);
     }
 
-    public void addItem(WorkspaceItemInfo item) {
+    public void addItem(ItemInfo item) {
         mInfo.add(item, true);
     }
 
-    public void removeItem(WorkspaceItemInfo item, boolean animate) {
+    public void removeItem(ItemInfo item, boolean animate) {
         mInfo.remove(item, animate);
     }
 
@@ -285,8 +286,8 @@
         mOpenAlarm.setOnAlarmListener(mOnOpenListener);
         if (SPRING_LOADING_ENABLED &&
                 ((dragInfo instanceof WorkspaceItemFactory)
-                        || (dragInfo instanceof WorkspaceItemInfo)
-                        || (dragInfo instanceof PendingAddShortcutInfo))) {
+                        || (dragInfo instanceof PendingAddShortcutInfo)
+                        || Folder.willAccept(dragInfo))) {
             mOpenAlarm.setAlarm(ON_OPEN_DELAY);
         }
     }
@@ -301,8 +302,8 @@
         return mPreviewItemManager.prepareCreateAnimation(destView);
     }
 
-    public void performCreateAnimation(final WorkspaceItemInfo destInfo, final View destView,
-            final WorkspaceItemInfo srcInfo, final DragObject d, Rect dstRect,
+    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);
@@ -328,7 +329,7 @@
         mOpenAlarm.cancelAlarm();
     }
 
-    private void onDrop(final WorkspaceItemInfo item, DragObject d, Rect finalRect,
+    private void onDrop(final ItemInfo item, DragObject d, Rect finalRect,
             float scaleRelativeToDragLayer, int index, boolean itemReturnedOnFailedDrop) {
         item.cellX = -1;
         item.cellY = -1;
@@ -359,7 +360,7 @@
             int numItemsInPreview = Math.min(MAX_NUM_ITEMS_IN_PREVIEW, index + 1);
             boolean itemAdded = false;
             if (itemReturnedOnFailedDrop || index >= MAX_NUM_ITEMS_IN_PREVIEW) {
-                List<WorkspaceItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
+                List<ItemInfo> oldPreviewItems = new ArrayList<>(mCurrentPreviewItems);
                 mInfo.add(item, index, false);
                 mCurrentPreviewItems.clear();
                 mCurrentPreviewItems.addAll(getPreviewItemsOnPage(0));
@@ -420,7 +421,7 @@
             FolderNameInfos nameInfos = new FolderNameInfos();
             Executors.MODEL_EXECUTOR.post(() -> {
                 d.folderNameProvider.getSuggestedFolderName(
-                        getContext(), mInfo.contents, nameInfos);
+                        getContext(), mInfo.getAppContents(), nameInfos);
                 postDelayed(() -> {
                     setLabelSuggestion(nameInfos, d.logInstanceId);
                     invalidate();
@@ -473,19 +474,25 @@
 
 
     public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) {
-        WorkspaceItemInfo item;
+        ItemInfo item;
         if (d.dragInfo instanceof WorkspaceItemFactory) {
             // Came from all apps -- make a copy
             item = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(getContext());
         } else if (d.dragSource instanceof BaseItemDragListener){
             // Came from a different window -- make a copy
-            item = new WorkspaceItemInfo((WorkspaceItemInfo) d.dragInfo);
+            if (d.dragInfo instanceof AppPairInfo) {
+                // dragged item is app pair
+                item = new AppPairInfo((AppPairInfo) d.dragInfo);
+            } else {
+                // dragged item is WorkspaceItemInfo
+                item = new WorkspaceItemInfo((WorkspaceItemInfo) d.dragInfo);
+            }
         } else {
-            item = (WorkspaceItemInfo) d.dragInfo;
+            item = d.dragInfo;
         }
         mFolder.notifyDrop();
         onDrop(item, d, null, 1.0f,
-                itemReturnedOnFailedDrop ? item.rank : mInfo.contents.size(),
+                itemReturnedOnFailedDrop ? item.rank : mInfo.getContents().size(),
                 itemReturnedOnFailedDrop
         );
     }
@@ -633,6 +640,20 @@
         }
     }
 
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        boolean shouldCenterIcon = mActivity.getDeviceProfile().iconCenterVertically;
+        if (shouldCenterIcon) {
+            int iconSize = mActivity.getDeviceProfile().iconSizePx;
+            Paint.FontMetrics fm = mFolderName.getPaint().getFontMetrics();
+            int cellHeightPx = iconSize + mFolderName.getCompoundDrawablePadding()
+                    + (int) Math.ceil(fm.bottom - fm.top);
+            setPadding(getPaddingLeft(), (MeasureSpec.getSize(heightMeasureSpec)
+                    - cellHeightPx) / 2, getPaddingRight(), getPaddingBottom());
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
     /** Sets the visibility of the icon's title text */
     public void setTextVisible(boolean visible) {
         if (visible) {
@@ -649,8 +670,8 @@
     /**
      * Returns the list of items which should be visible in the preview
      */
-    public List<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
-        return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.contents);
+    public List<ItemInfo> getPreviewItemsOnPage(int page) {
+        return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.getContents());
     }
 
     @Override
@@ -674,12 +695,12 @@
     /**
      * Updates the preview items which match the provided condition
      */
-    public void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
+    public void updatePreviewItems(Predicate<ItemInfo> itemCheck) {
         mPreviewItemManager.updatePreviewItems(itemCheck);
     }
 
     @Override
-    public void onAdd(WorkspaceItemInfo item, int rank) {
+    public void onAdd(ItemInfo item, int rank) {
         updatePreviewItems(false);
         boolean wasDotted = mDotInfo.hasDot();
         mDotInfo.addDotInfo(mActivity.getDotInfoForItem(item));
@@ -691,7 +712,7 @@
     }
 
     @Override
-    public void onRemove(List<WorkspaceItemInfo> items) {
+    public void onRemove(List<ItemInfo> items) {
         updatePreviewItems(false);
         boolean wasDotted = mDotInfo.hasDot();
         items.stream().map(mActivity::getDotInfoForItem).forEach(mDotInfo::subtractDotInfo);
@@ -702,6 +723,7 @@
         requestLayout();
     }
 
+    @Override
     public void onTitleChanged(CharSequence title) {
         mFolderName.setText(title);
         setContentDescription(getAccessiblityTitle(title));
@@ -793,7 +815,7 @@
      * Returns a formatted accessibility title for folder
      */
     public String getAccessiblityTitle(CharSequence title) {
-        int size = mInfo.contents.size();
+        int size = mInfo.getContents().size();
         if (size < MAX_NUM_ITEMS_IN_PREVIEW) {
             return getContext().getString(R.string.folder_name_format_exact, title, size);
         } else {
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index bf59594..5d2bb3a 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -35,7 +35,7 @@
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.IntSparseArrayMap;
 import com.android.launcher3.util.Preconditions;
@@ -62,7 +62,7 @@
      * name edit box can also be used to provide suggestion.
      */
     public static final int SUGGEST_MAX = 4;
-    protected IntSparseArrayMap<FolderInfo> mFolderInfos;
+    protected IntSparseArrayMap<CollectionInfo> mCollectionInfos;
     protected List<AppInfo> mAppInfos;
 
     /**
@@ -79,7 +79,7 @@
     }
 
     public static FolderNameProvider newInstance(Context context, List<AppInfo> appInfos,
-            IntSparseArrayMap<FolderInfo> folderInfos) {
+            IntSparseArrayMap<CollectionInfo> folderInfos) {
         Preconditions.assertWorkerThread();
         FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
                 context.getApplicationContext(), R.string.folder_name_provider_class);
@@ -93,9 +93,9 @@
                 new FolderNameWorker());
     }
 
-    private void load(List<AppInfo> appInfos, IntSparseArrayMap<FolderInfo> folderInfos) {
+    private void load(List<AppInfo> appInfos, IntSparseArrayMap<CollectionInfo> folderInfos) {
         mAppInfos = appInfos;
-        mFolderInfos = folderInfos;
+        mCollectionInfos = folderInfos;
     }
 
     /**
@@ -195,7 +195,7 @@
         @Override
         public void execute(@NonNull final LauncherAppState app,
                 @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-            mFolderInfos = dataModel.folders.clone();
+            mCollectionInfos = dataModel.collections.clone();
             mAppInfos = Arrays.asList(apps.copyData());
         }
     }
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index f2bed92..8eaa0dc 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -41,8 +41,10 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.celllayout.CellLayoutLayoutParams;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
+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.PageIndicatorDots;
@@ -148,7 +150,7 @@
     /**
      * Binds items to the layout.
      */
-    public void bindItems(List<WorkspaceItemInfo> items) {
+    public void bindItems(List<ItemInfo> items) {
         if (mViewsBound) {
             unbindItems();
         }
@@ -164,8 +166,11 @@
             CellLayout page = (CellLayout) getChildAt(i);
             ShortcutAndWidgetContainer container = page.getShortcutsAndWidgets();
             for (int j = container.getChildCount() - 1; j >= 0; j--) {
-                container.getChildAt(j).setVisibility(View.VISIBLE);
-                mViewCache.recycleView(R.layout.folder_application, container.getChildAt(j));
+                View iconView = container.getChildAt(j);
+                iconView.setVisibility(View.VISIBLE);
+                if (iconView instanceof BubbleTextView) {
+                    mViewCache.recycleView(R.layout.folder_application, iconView);
+                }
             }
             page.removeAllViews();
             mViewCache.recycleView(R.layout.folder_page, page);
@@ -185,7 +190,7 @@
      * Creates and adds an icon corresponding to the provided rank
      * @return the created icon
      */
-    public View createAndAddViewForRank(WorkspaceItemInfo item, int rank) {
+    public View createAndAddViewForRank(ItemInfo item, int rank) {
         View icon = createNewView(item);
         if (!mViewsBound) {
             return icon;
@@ -200,7 +205,7 @@
      * Adds the {@param view} to the layout based on {@param rank} and updated the position
      * related attributes. It assumes that {@param item} is already attached to the view.
      */
-    public void addViewForRank(View view, WorkspaceItemInfo item, int rank) {
+    public void addViewForRank(View view, ItemInfo item, int rank) {
         int pageNo = rank / mOrganizer.getMaxItemsPerPage();
 
         CellLayoutLayoutParams lp = (CellLayoutLayoutParams) view.getLayoutParams();
@@ -209,26 +214,36 @@
     }
 
     @SuppressLint("InflateParams")
-    public View createNewView(WorkspaceItemInfo item) {
+    public View createNewView(ItemInfo item) {
         if (item == null) {
             return null;
         }
-        final BubbleTextView textView = mViewCache.getView(
-                R.layout.folder_application, getContext(), null);
-        textView.applyFromWorkspaceItem(item);
-        textView.setOnClickListener(mFolder.mActivityContext.getItemOnClickListener());
-        textView.setOnLongClickListener(mFolder);
-        textView.setOnFocusChangeListener(mFocusIndicatorHelper);
-        CellLayoutLayoutParams lp = (CellLayoutLayoutParams) textView.getLayoutParams();
+
+        final View icon;
+        if (item instanceof AppPairInfo api) {
+            // TODO (b/332607759): Make view cache work with app pair icons
+            icon = AppPairIcon.inflateIcon(R.layout.folder_app_pair, ActivityContext.lookupContext(
+                    getContext()), null , api, BubbleTextView.DISPLAY_FOLDER);
+        } else {
+            icon = mViewCache.getView(R.layout.folder_application, getContext(), null);
+            ((BubbleTextView) icon).applyFromWorkspaceItem((WorkspaceItemInfo) item);
+        }
+
+        icon.setOnClickListener(mFolder.mActivityContext.getItemOnClickListener());
+        icon.setOnLongClickListener(mFolder);
+        icon.setOnFocusChangeListener(mFocusIndicatorHelper);
+
+        CellLayoutLayoutParams lp = (CellLayoutLayoutParams) icon.getLayoutParams();
         if (lp == null) {
-            textView.setLayoutParams(new CellLayoutLayoutParams(
+            icon.setLayoutParams(new CellLayoutLayoutParams(
                     item.cellX, item.cellY, item.spanX, item.spanY));
         } else {
             lp.setCellX(item.cellX);
             lp.setCellY(item.cellY);
             lp.cellHSpan = lp.cellVSpan = 1;
         }
-        return textView;
+
+        return icon;
     }
 
     @Nullable
@@ -497,13 +512,20 @@
         if (page != null) {
             ShortcutAndWidgetContainer parent = page.getShortcutsAndWidgets();
             for (int i = parent.getChildCount() - 1; i >= 0; i--) {
-                BubbleTextView icon = ((BubbleTextView) parent.getChildAt(i));
-                icon.verifyHighRes();
+                View iconView = parent.getChildAt(i);
+                Drawable d = null;
+                if (iconView instanceof BubbleTextView btv) {
+                    btv.verifyHighRes();
+                    d = btv.getIcon();
+                } else if (iconView instanceof AppPairIcon api) {
+                    api.verifyHighRes();
+                    d = api.getIconDrawableArea().getDrawable();
+                }
+
                 // Set the callback back to the actual icon, in case
                 // it was captured by the FolderIcon
-                Drawable d = icon.getIcon();
                 if (d != null) {
-                    d.setCallback(icon);
+                    d.setCallback(iconView);
                 }
             }
         }
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 66c9109..07215c4 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -33,7 +33,7 @@
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.data.FolderInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -86,15 +86,16 @@
                 FolderInfo info = folder.mInfo;
                 if (itemCount <= 1) {
                     View newIcon = null;
-                    WorkspaceItemInfo finalItem = null;
+                    ItemInfo finalItem = null;
 
                     if (itemCount == 1) {
                         // Move the item from the folder to the workspace, in the position of the
                         // folder
                         CellLayout cellLayout = mLauncher.getCellLayout(info.container,
                                 mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
-                        finalItem =  info.contents.remove(0);
-                        newIcon = mLauncher.createShortcut(cellLayout, finalItem);
+                        finalItem =  info.getContents().remove(0);
+                        newIcon = mLauncher.getItemInflater().inflateItem(
+                                finalItem, mLauncher.getModelWriter(), cellLayout);
                         mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
                                 info.container, info.screenId, info.cellX, info.cellY);
                     }
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index 58efdc1..0faa1c9 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -17,7 +17,7 @@
 
 import android.graphics.drawable.Drawable;
 
-import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.model.data.ItemInfo;
 
 /**
  * Manages the parameters used to draw a Folder preview item.
@@ -30,7 +30,7 @@
     public FolderPreviewItemAnim anim;
     public boolean hidden;
     public Drawable drawable;
-    public WorkspaceItemInfo item;
+    public ItemInfo item;
 
     PreviewItemDrawingParams(float transX, float transY, float scale) {
         this.transX = transX;
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index b39e968e..6311638 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.folder;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_FOLDER;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ENTER_INDEX;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.EXIT_INDEX;
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
@@ -37,10 +38,16 @@
 import android.view.View;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.apppairs.AppPairIcon;
+import com.android.launcher3.apppairs.AppPairIconDrawingParams;
+import com.android.launcher3.apppairs.AppPairIconGraphic;
 import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.Themes;
@@ -71,7 +78,8 @@
 
     private final Context mContext;
     private final FolderIcon mIcon;
-    private final int mIconSize;
+    @VisibleForTesting
+    public final int mIconSize;
 
     // These variables are all associated with the drawing of the preview; they are stored
     // as member variables for shared usage and to avoid computation on each frame
@@ -117,13 +125,15 @@
             final Runnable onCompleteRunnable) {
         return reverse
                 ? new FolderPreviewItemAnim(this, mFirstPageParams.get(0), 0, 2, -1, -1,
-                        FINAL_ITEM_ANIMATION_DURATION, onCompleteRunnable)
+                FINAL_ITEM_ANIMATION_DURATION, onCompleteRunnable)
                 : new FolderPreviewItemAnim(this, mFirstPageParams.get(0), -1, -1, 0, 2,
                         INITIAL_ITEM_ANIMATION_DURATION, onCompleteRunnable);
     }
 
     Drawable prepareCreateAnimation(final View destView) {
-        Drawable animateDrawable = ((BubbleTextView) destView).getIcon();
+        Drawable animateDrawable = destView instanceof AppPairIcon
+                ? ((AppPairIcon) destView).getIconDrawableArea().getDrawable()
+                : ((BubbleTextView) destView).getIcon();
         computePreviewDrawingParams(animateDrawable.getIntrinsicWidth(),
                 destView.getMeasuredWidth());
         mReferenceDrawable = animateDrawable;
@@ -217,9 +227,9 @@
     /**
      * Draws each preview item.
      *
-     * @param offset The offset needed to draw the preview items.
+     * @param offset         The offset needed to draw the preview items.
      * @param shouldClipPath Iff true, clip path using {@param clipPath}.
-     * @param clipPath The clip path of the folder icon.
+     * @param clipPath       The clip path of the folder icon.
      */
     private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params, PointF offset,
             boolean shouldClipPath, Path clipPath) {
@@ -256,7 +266,7 @@
     }
 
     void buildParamsForPage(int page, ArrayList<PreviewItemDrawingParams> params, boolean animate) {
-        List<WorkspaceItemInfo> items = mIcon.getPreviewItemsOnPage(page);
+        List<ItemInfo> items = mIcon.getPreviewItemsOnPage(page);
 
         // We adjust the size of the list to match the number of items in the preview.
         while (items.size() < params.size()) {
@@ -326,16 +336,18 @@
         mNumOfPrevItems = numOfPrevItemsAux;
     }
 
-    void updatePreviewItems(Predicate<WorkspaceItemInfo> itemCheck) {
+    void updatePreviewItems(Predicate<ItemInfo> itemCheck) {
         boolean modified = false;
         for (PreviewItemDrawingParams param : mFirstPageParams) {
-            if (itemCheck.test(param.item)) {
+            if (itemCheck.test(param.item)
+                    || (param.item instanceof AppPairInfo api && api.anyMatch(itemCheck))) {
                 setDrawable(param, param.item);
                 modified = true;
             }
         }
         for (PreviewItemDrawingParams param : mCurrentPageParams) {
-            if (itemCheck.test(param.item)) {
+            if (itemCheck.test(param.item)
+                    || (param.item instanceof AppPairInfo api && api.anyMatch(itemCheck))) {
                 setDrawable(param, param.item);
                 modified = true;
             }
@@ -360,23 +372,22 @@
 
     /**
      * Handles the case where items in the preview are either:
-     *  - Moving into the preview
-     *  - Moving into a new position
-     *  - Moving out of the preview
+     * - Moving into the preview
+     * - Moving into a new position
+     * - Moving out of the preview
      *
      * @param oldItems The list of items in the old preview.
      * @param newItems The list of items in the new preview.
-     * @param dropped The item that was dropped onto the FolderIcon.
+     * @param dropped  The item that was dropped onto the FolderIcon.
      */
-    public void onDrop(List<WorkspaceItemInfo> oldItems, List<WorkspaceItemInfo> newItems,
-            WorkspaceItemInfo dropped) {
+    public void onDrop(List<ItemInfo> oldItems, List<ItemInfo> newItems, ItemInfo dropped) {
         int numItems = newItems.size();
         final ArrayList<PreviewItemDrawingParams> params = mFirstPageParams;
         buildParamsForPage(0, params, false);
 
         // New preview items for items that are moving in (except for the dropped item).
-        List<WorkspaceItemInfo> moveIn = new ArrayList<>();
-        for (WorkspaceItemInfo newItem : newItems) {
+        List<ItemInfo> moveIn = new ArrayList<>();
+        for (ItemInfo newItem : newItems) {
             if (!oldItems.contains(newItem) && !newItem.equals(dropped)) {
                 moveIn.add(newItem);
             }
@@ -399,10 +410,10 @@
         }
 
         // Old preview items that need to be moved out.
-        List<WorkspaceItemInfo> moveOut = new ArrayList<>(oldItems);
+        List<ItemInfo> moveOut = new ArrayList<>(oldItems);
         moveOut.removeAll(newItems);
         for (int i = 0; i < moveOut.size(); ++i) {
-            WorkspaceItemInfo item = moveOut.get(i);
+            ItemInfo item = moveOut.get(i);
             int oldIndex = oldItems.indexOf(item);
             PreviewItemDrawingParams p = computePreviewItemDrawingParams(oldIndex, numItems, null);
             updateTransitionParam(p, item, oldIndex, EXIT_INDEX, numItems);
@@ -416,7 +427,7 @@
         }
     }
 
-    private void updateTransitionParam(final PreviewItemDrawingParams p, WorkspaceItemInfo item,
+    private void updateTransitionParam(final PreviewItemDrawingParams p, ItemInfo item,
             int prevIndex, int newIndex, int numItems) {
         setDrawable(p, item);
 
@@ -428,19 +439,26 @@
         p.anim = anim;
     }
 
-    private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
-        if (item.hasPromiseIconUi() || (item.runtimeStatusFlags
+    @VisibleForTesting
+    public void setDrawable(PreviewItemDrawingParams p, ItemInfo item) {
+        if (item instanceof WorkspaceItemInfo wii) {
+            if (wii.hasPromiseIconUi() || (wii.runtimeStatusFlags
                     & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
-            PreloadIconDrawable drawable = newPendingIcon(mContext, item);
-            drawable.setLevel(item.getProgressLevel());
-            p.drawable = drawable;
-        } else {
-            p.drawable = item.newIcon(mContext,
-                    Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
+                PreloadIconDrawable drawable = newPendingIcon(mContext, wii);
+                p.drawable = drawable;
+            } else {
+                p.drawable = wii.newIcon(mContext,
+                        Themes.isThemedIconEnabled(mContext) ? FLAG_THEMED : 0);
+            }
+            p.drawable.setBounds(0, 0, mIconSize, mIconSize);
+        } else if (item instanceof AppPairInfo api) {
+            AppPairIconDrawingParams appPairParams =
+                    new AppPairIconDrawingParams(mContext, DISPLAY_FOLDER);
+            p.drawable = AppPairIconGraphic.composeDrawable(api, appPairParams);
+            p.drawable.setBounds(0, 0, mIconSize, mIconSize);
         }
-        p.drawable.setBounds(0, 0, mIconSize, mIconSize);
-        p.item = item;
 
+        p.item = item;
         // Set the callback to FolderIcon as it is responsible to drawing the icon. The
         // callback will be released when the folder is opened.
         p.drawable.setCallback(mIcon);
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 18200f6..dc8694d 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -19,7 +19,6 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.Themes.isThemedIconEnabled;
 
-import android.annotation.TargetApi;
 import android.content.ContentProvider;
 import android.content.ContentValues;
 import android.content.pm.PackageManager;
@@ -27,7 +26,6 @@
 import android.database.MatrixCursor;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -41,7 +39,6 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile.GridOption;
 import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.util.Executors;
 
 /**
@@ -184,13 +181,12 @@
             return null;
         }
 
-        if (!Utilities.ATLEAST_R || !METHOD_GET_PREVIEW.equals(method)) {
+        if (!METHOD_GET_PREVIEW.equals(method)) {
             return null;
         }
         return getPreview(extras);
     }
 
-    @TargetApi(Build.VERSION_CODES.R)
     private synchronized Bundle getPreview(Bundle request) {
         PreviewLifecycleObserver observer = null;
         try {
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 3330448..50d2b43 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -20,13 +20,14 @@
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 import static android.view.View.VISIBLE;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
+import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE;
 import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
 import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
 import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
 
-import android.annotation.TargetApi;
 import android.app.Fragment;
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
@@ -35,10 +36,10 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.AttributeSet;
@@ -65,7 +66,6 @@
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -81,14 +81,12 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.uioverrides.PredictedAppIconInflater;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.IntArray;
@@ -102,7 +100,6 @@
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 import com.android.launcher3.widget.LocalColorExtractor;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.ArrayList;
@@ -120,7 +117,6 @@
  *   3) Place appropriate elements like icons and first-page qsb
  *   4) Measure and draw the view on a canvas
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class LauncherPreviewRenderer extends ContextWrapper
         implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
 
@@ -135,13 +131,10 @@
                 new ConcurrentLinkedQueue<>();
 
         public PreviewContext(Context base, InvariantDeviceProfile idp) {
-            super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
-                    LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
-                    CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
-                    WindowManagerProxy.INSTANCE, DisplayController.INSTANCE);
+            super(base);
             mIdp = idp;
-            mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
-            mObjectMap.put(LauncherAppState.INSTANCE,
+            putObject(InvariantDeviceProfile.INSTANCE, idp);
+            putObject(LauncherAppState.INSTANCE,
                     new LauncherAppState(this, null /* iconCacheFileName */));
         }
 
@@ -197,7 +190,7 @@
         mUiHandler = new Handler(Looper.getMainLooper());
         mContext = context;
         mIdp = idp;
-        mDp = idp.getDeviceProfile(context).toBuilder(context).setViewScaleProvider(
+        mDp = getDeviceProfileForPreview(context).toBuilder(context).setViewScaleProvider(
                 this::getAppWidgetScale).build();
         if (context instanceof PreviewContext) {
             Context tempContext = ((PreviewContext) context).getBaseContext();
@@ -260,6 +253,21 @@
     }
 
     /**
+     * Returns the device profile based on resource configuration for previewing various display
+     * sizes
+     */
+    private DeviceProfile getDeviceProfileForPreview(Context context) {
+        float density = context.getResources().getDisplayMetrics().density;
+        Configuration config = context.getResources().getConfiguration();
+
+        return mIdp.getBestMatch(
+                config.screenWidthDp * density,
+                config.screenHeightDp * density,
+                WindowManagerProxy.INSTANCE.get(context).getRotation(context)
+        );
+    }
+
+    /**
      * Returns the insets of the screen closest to the display given by the context
      */
     private Rect getInsets(Context context) {
@@ -374,14 +382,16 @@
         addInScreenFromBind(icon, info);
     }
 
-    private void inflateAndAddCollectionIcon(FolderInfo info) {
-        CellLayout screen = info.container == Favorites.CONTAINER_DESKTOP
+    private void inflateAndAddCollectionIcon(CollectionInfo info) {
+        boolean isOnDesktop = info.container == Favorites.CONTAINER_DESKTOP;
+        CellLayout screen = isOnDesktop
                 ? mWorkspaceScreens.get(info.screenId)
                 : mHotseat;
-        FrameLayout folderIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
-                ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, info)
-                : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, info);
-        addInScreenFromBind(folderIcon, info);
+        FrameLayout collectionIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
+                ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, (FolderInfo) info)
+                : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, (AppPairInfo) info,
+                        isOnDesktop ? DISPLAY_WORKSPACE : DISPLAY_TASKBAR);
+        addInScreenFromBind(collectionIcon, info);
     }
 
     private void inflateAndAddWidgets(
@@ -401,7 +411,7 @@
 
     private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
         WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
-                info.providerName, info.user);
+                info.providerName, info.user, mContext);
         if (widgetItem == null) {
             return;
         }
@@ -440,10 +450,10 @@
 
     private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
         CellLayout screen = mWorkspaceScreens.get(info.screenId);
-        View view = PredictedAppIconInflater.inflate(mHomeElementInflater, screen, info);
-        if (view != null) {
-            addInScreenFromBind(view, info);
-        }
+        BubbleTextView icon = (BubbleTextView) mHomeElementInflater.inflate(
+                R.layout.predicted_app_icon, screen, false);
+        icon.applyFromWorkspaceItem(info);
+        addInScreenFromBind(icon, info);
     }
 
     private void dispatchVisibilityAggregated(View view, boolean isVisible) {
@@ -485,7 +495,7 @@
                     break;
                 case Favorites.ITEM_TYPE_FOLDER:
                 case Favorites.ITEM_TYPE_APP_PAIR:
-                    inflateAndAddCollectionIcon((FolderInfo) itemInfo);
+                    inflateAndAddCollectionIcon((CollectionInfo) itemInfo);
                     break;
                 default:
                     break;
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 3e77c78..9fffcc1 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -173,6 +173,8 @@
         mIconScaleMultiplier.updateValue(info.getProgressLevel() == 0 ? 0 : 1);
 
         setLevel(info.getProgressLevel());
+        // Set a disabled icon color if the app is suspended or if the app is pending download
+        setIsDisabled(info.isDisabled() || info.isPendingDownload());
     }
 
     @Override
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 683354b..addd072 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -37,7 +37,6 @@
 import android.view.SurfaceControlViewHost;
 import android.view.SurfaceControlViewHost.SurfacePackage;
 import android.view.View;
-import android.view.WindowManager.LayoutParams;
 import android.view.animation.AccelerateDecelerateInterpolator;
 
 import androidx.annotation.NonNull;
@@ -49,13 +48,12 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
 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.GridSizeMigrationUtil;
-import com.android.launcher3.model.LauncherBinder;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.provider.LauncherDbUtils;
@@ -88,6 +86,7 @@
     private final int mHeight;
     private String mGridName;
 
+    private final int mDisplayId;
     private final Display mDisplay;
     private final WallpaperColors mWallpaperColors;
     private final RunnableList mOnDestroyCallbacks = new RunnableList();
@@ -111,8 +110,12 @@
         mHostToken = bundle.getBinder(KEY_HOST_TOKEN);
         mWidth = bundle.getInt(KEY_VIEW_WIDTH);
         mHeight = bundle.getInt(KEY_VIEW_HEIGHT);
+        mDisplayId = bundle.getInt(KEY_DISPLAY_ID);
         mDisplay = context.getSystemService(DisplayManager.class)
-                .getDisplay(bundle.getInt(KEY_DISPLAY_ID));
+                .getDisplay(mDisplayId);
+        if (mDisplay == null) {
+            throw new IllegalArgumentException("Display ID does not match any displays.");
+        }
 
         mSurfaceControlViewHost = MAIN_EXECUTOR.submit(() ->
                 new SurfaceControlViewHost(mContext, context.getSystemService(DisplayManager.class)
@@ -122,7 +125,7 @@
     }
 
     public int getDisplayId() {
-        return mDisplay.getDisplayId();
+        return mDisplayId;
     }
 
     public IBinder getHostToken() {
@@ -211,10 +214,6 @@
             return new ContextThemeWrapper(context,
                     Themes.getActivityThemeRes(context));
         }
-        if (Utilities.ATLEAST_R) {
-            context = context.createWindowContext(
-                    LayoutParams.TYPE_APPLICATION_OVERLAY, null);
-        }
         LocalColorExtractor.newInstance(context)
                 .applyColorsOverride(context, mWallpaperColors);
         return new ContextThemeWrapper(context,
@@ -245,7 +244,7 @@
                     /* bgAllAppsList= */ null,
                     bgModel,
                     LauncherAppState.getInstance(previewContext).getModel().getModelDelegate(),
-                    new LauncherBinder(LauncherAppState.getInstance(previewContext), bgModel,
+                    new BaseLauncherBinder(LauncherAppState.getInstance(previewContext), bgModel,
                             /* bgAllAppsList= */ null, new Callbacks[0])) {
 
                 @Override
@@ -259,7 +258,7 @@
                         query += " or " + LauncherSettings.Favorites.SCREEN + " = "
                                 + Workspace.SECOND_SCREEN_ID;
                     }
-                    loadWorkspace(new ArrayList<>(), query, null);
+                    loadWorkspace(new ArrayList<>(), query, null, null);
 
                     final SparseArray<Size> spanInfo =
                             getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 2f7f51e..329f717 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -37,6 +37,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteException;
 import android.graphics.drawable.Drawable;
+import android.os.Looper;
 import android.os.Process;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -44,17 +45,18 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.util.Pair;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
 import com.android.launcher3.icons.cache.BaseIconCache;
 import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.IconRequestInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -63,9 +65,9 @@
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.widget.WidgetSections;
 import com.android.launcher3.widget.WidgetSections.WidgetSection;
 
@@ -100,7 +102,7 @@
     private final UserCache mUserManager;
     private final InstantAppResolver mInstantAppResolver;
     private final IconProvider mIconProvider;
-    private final HandlerRunnable mCancelledRunnable;
+    private final CancellableTask mCancelledTask;
 
     private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos;
 
@@ -119,9 +121,8 @@
         mIconProvider = iconProvider;
         mWidgetCategoryBitmapInfos = new SparseArray<>();
 
-        mCancelledRunnable = new HandlerRunnable(
-                mWorkerHandler, () -> null, MAIN_EXECUTOR, c -> { });
-        mCancelledRunnable.cancel();
+        mCancelledTask = new CancellableTask(() -> null, MAIN_EXECUTOR, c -> { });
+        mCancelledTask.cancel();
     }
 
     @Override
@@ -174,9 +175,9 @@
      *
      * @return a request ID that can be used to cancel the request.
      */
-    public HandlerRunnable updateIconInBackground(final ItemInfoUpdateReceiver caller,
+    @AnyThread
+    public CancellableTask updateIconInBackground(final ItemInfoUpdateReceiver caller,
             final ItemInfoWithIcon info) {
-        Preconditions.assertUIThread();
         Supplier<ItemInfoWithIcon> task;
         if (info instanceof AppInfo || info instanceof WorkspaceItemInfo) {
             task = () -> {
@@ -191,16 +192,22 @@
         } else {
             Log.i(TAG, "Icon update not supported for "
                     + info == null ? "null" : info.getClass().getName());
-            return mCancelledRunnable;
+            return mCancelledTask;
         }
 
-        if (mPendingIconRequestCount <= 0) {
-            MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+        Runnable endRunnable;
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            if (mPendingIconRequestCount <= 0) {
+                MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+            }
+            mPendingIconRequestCount++;
+            endRunnable = this::onIconRequestEnd;
+        } else {
+            endRunnable = () -> { };
         }
-        mPendingIconRequestCount++;
 
-        HandlerRunnable<ItemInfoWithIcon> request = new HandlerRunnable<>(mWorkerHandler,
-                task, MAIN_EXECUTOR, caller::reapplyItemInfo, this::onIconRequestEnd);
+        CancellableTask<ItemInfoWithIcon> request = new CancellableTask<>(
+                task, MAIN_EXECUTOR, caller::reapplyItemInfo, endRunnable);
         Utilities.postAsyncCallback(mWorkerHandler, request);
         return request;
     }
@@ -216,10 +223,22 @@
      * Updates {@param application} only if a valid entry is found.
      */
     public synchronized void updateTitleAndIcon(AppInfo application) {
+        boolean preferPackageIcon = application.isArchived();
         CacheEntry entry = cacheLocked(application.componentName,
                 application.user, () -> null, mLauncherActivityInfoCachingLogic,
                 false, application.usingLowResIcon());
-        if (entry.bitmap != null && !isDefaultIcon(entry.bitmap, application.user)) {
+        if (entry.bitmap == null || isDefaultIcon(entry.bitmap, application.user)) {
+            return;
+        }
+
+        if (preferPackageIcon) {
+            String packageName = application.getTargetPackage();
+            CacheEntry packageEntry =
+                    cacheLocked(new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                            application.user, () -> null, mLauncherActivityInfoCachingLogic,
+                            true, application.usingLowResIcon());
+            applyPackageEntry(packageEntry, application, entry);
+        } else {
             applyCacheEntry(entry, application);
         }
     }
@@ -227,10 +246,14 @@
     /**
      * Fill in {@param info} with the icon and label for {@param activityInfo}
      */
+    @SuppressWarnings("NewApi")
     public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
             LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+        boolean isAppArchived = Flags.enableSupportForArchiving() && activityInfo != null
+                && activityInfo.getActivityInfo().isArchived;
         // If we already have activity info, no need to use package icon
-        getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon);
+        getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon,
+                isAppArchived);
     }
 
     /**
@@ -309,7 +332,7 @@
         } else {
             Intent intent = info.getIntent();
             getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
-                    true, useLowResIcon);
+                    true, useLowResIcon, info.isArchived());
         }
     }
 
@@ -334,6 +357,28 @@
     }
 
     /**
+     * Fill in {@param mWorkspaceItemInfo} with the icon and label for {@param info}
+     */
+    public synchronized void getTitleAndIcon(
+            @NonNull ItemInfoWithIcon infoInOut,
+            @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
+            boolean usePkgIcon, boolean useLowResIcon, boolean preferPackageEntry) {
+        CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+                activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon,
+                useLowResIcon);
+        if (preferPackageEntry) {
+            String packageName = infoInOut.getTargetPackage();
+            CacheEntry packageEntry = cacheLocked(
+                    new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                    infoInOut.user, activityInfoProvider, mLauncherActivityInfoCachingLogic,
+                    usePkgIcon, useLowResIcon);
+            applyPackageEntry(packageEntry, infoInOut, entry);
+        } else {
+            applyCacheEntry(entry, infoInOut);
+        }
+    }
+
+    /**
      * Creates an sql cursor for a query of a set of ItemInfoWithIcon icons and titles.
      *
      * @param iconRequestInfos List of IconRequestInfos representing titles and icons to query.
@@ -425,17 +470,22 @@
                         duplicateIconRequestsMap.get(cn);
 
                 if (cn != null) {
-                    CacheEntry entry = cacheLocked(
-                            cn,
-                            /* user = */ sectionKey.first,
-                            () -> duplicateIconRequests.get(0).launcherActivityInfo,
-                            mLauncherActivityInfoCachingLogic,
-                            c,
-                            /* usePackageIcon= */ false,
-                            /* useLowResIcons = */ sectionKey.second);
+                    if (duplicateIconRequests != null) {
+                        CacheEntry entry = cacheLocked(
+                                cn,
+                                /* user = */ sectionKey.first,
+                                () -> duplicateIconRequests.get(0).launcherActivityInfo,
+                                mLauncherActivityInfoCachingLogic,
+                                c,
+                                /* usePackageIcon= */ false,
+                                /* useLowResIcons = */ sectionKey.second);
 
-                    for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
-                        applyCacheEntry(entry, iconRequest.itemInfo);
+                        for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
+                            applyCacheEntry(entry, iconRequest.itemInfo);
+                        }
+                    } else {
+                        Log.e(TAG, "Found entry in icon database but no main activity "
+                                + "entry for cn: " + cn);
                     }
                 }
             }
@@ -522,7 +572,7 @@
         try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
             final BitmapInfo tempBitmap = li.createBadgedIconBitmap(
                     mContext.getDrawable(widgetSection.mSectionDrawable),
-                    new BaseIconFactory.IconOptions().setShrinkNonAdaptiveIcons(false));
+                    new BaseIconFactory.IconOptions());
             mWidgetCategoryBitmapInfos.put(infoInOut.widgetCategory, tempBitmap);
             infoInOut.bitmap = getBadgedIcon(tempBitmap, infoInOut.user);
         } catch (Exception e) {
@@ -551,6 +601,19 @@
         }
     }
 
+    protected void applyPackageEntry(@NonNull final CacheEntry packageEntry,
+            @NonNull final ItemInfoWithIcon info, @NonNull final CacheEntry fallbackEntry) {
+        info.title = Utilities.trim(packageEntry.title);
+        info.appTitle = Utilities.trim(fallbackEntry.title);
+        info.contentDescription = packageEntry.contentDescription;
+        info.bitmap = packageEntry.bitmap;
+        if (packageEntry.bitmap == null) {
+            // TODO: entry.bitmap can never be null, so this should not happen at all.
+            Log.wtf(TAG, "Cannot find bitmap from the cache, default icon was loaded.");
+            info.bitmap = getDefaultIcon(info.user);
+        }
+    }
+
     public Drawable getFullResIcon(LauncherActivityInfo info) {
         return mIconProvider.getIcon(info, mIconDpi);
     }
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index a15348b..513377a 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -16,14 +16,13 @@
 
 package com.android.launcher3.icons;
 
-import static com.android.launcher3.config.FeatureFlags.ENABLE_FORCED_MONO_ICON;
-
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.graphics.IconShape;
 import com.android.launcher3.graphics.LauncherPreviewRenderer;
@@ -103,7 +102,7 @@
     @Override
     protected Drawable getMonochromeDrawable(Drawable base) {
         Drawable mono = super.getMonochromeDrawable(base);
-        if (mono != null || !ENABLE_FORCED_MONO_ICON.get()) {
+        if (mono != null || !Flags.forceMonochromeAppIcons()) {
             return mono;
         }
         if (mMonochromeIconFactory == null) {
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
index 1791539..f40eda6 100644
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.icons;
 
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -101,7 +101,7 @@
      * Launcher specific checks
      */
     public static Drawable getIcon(Context context, ShortcutInfo shortcutInfo, int density) {
-        if (GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return null;
         }
         try {
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index 83003ff..72dc63e 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -20,7 +20,9 @@
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
 
 /**
  * A helper class to draw background of a focused view.
@@ -29,7 +31,11 @@
         implements OnFocusChangeListener {
 
     public FocusIndicatorHelper(View container) {
-        super(container, container.getResources().getColor(R.color.focused_background));
+        super(container,
+                Flags.enableFocusOutline() ? new int[]{Themes.getAttrColor(container.getContext(),
+                        R.attr.focusOutlineColor), Themes.getAttrColor(container.getContext(),
+                        R.attr.focusInnerOutlineColor)}
+                        : new int[]{container.getResources().getColor(R.color.focused_background)});
     }
 
     @Override
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
index 2476a6f..5e2832f 100644
--- a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -20,12 +20,12 @@
 import android.view.View;
 import android.view.View.OnFocusChangeListener;
 
-import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
-
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
 import androidx.recyclerview.widget.RecyclerView.State;
 
+import com.android.launcher3.keyboard.FocusIndicatorHelper.SimpleFocusIndicatorHelper;
+
 /**
  * {@link ItemDecoration} for drawing and animating focused view background.
  */
@@ -37,12 +37,17 @@
         mHelper = new SimpleFocusIndicatorHelper(container);
     }
 
+    public FocusedItemDecorator(FocusIndicatorHelper focusIndicatorHelper) {
+        mHelper = focusIndicatorHelper;
+    }
+
     public OnFocusChangeListener getFocusListener() {
         return mHelper;
     }
 
     @Override
-    public void onDraw(Canvas c, RecyclerView parent, State state) {
+    public void onDrawOver(Canvas c, RecyclerView parent, State state) {
+        // Use onDrawOver so focus outline is always visible
         mHelper.draw(c);
     }
 }
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 2dc8d81..456cde8 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -29,6 +29,7 @@
 import android.util.FloatProperty;
 import android.view.View;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
 
 /**
@@ -73,7 +74,8 @@
     private static final Rect sTempRect2 = new Rect();
 
     private final View mContainer;
-    protected final Paint mPaint;
+    protected final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final Paint mInnerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private final int mMaxAlpha;
 
     private final Rect mDirtyRect = new Rect();
@@ -92,23 +94,40 @@
     private ObjectAnimator mCurrentAnimation;
     private float mAlpha;
     private float mRadius;
+    private float mInnerRadius;
 
-    public ItemFocusIndicatorHelper(View container, int color) {
+    public ItemFocusIndicatorHelper(View container, int... colors) {
         mContainer = container;
 
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mMaxAlpha = Color.alpha(color);
-        mPaint.setColor(0xFF000000 | color);
+        mPaint.setColor(0xFF000000 | colors[0]);
+        if (Flags.enableFocusOutline() && colors.length > 1) {
+            mPaint.setStyle(Paint.Style.STROKE);
+            mPaint.setStrokeWidth(container.getResources().getDimensionPixelSize(
+                    R.dimen.focus_outline_stroke_width));
+            mRadius = container.getResources().getDimensionPixelSize(
+                    R.dimen.focus_outline_radius);
+
+            mInnerPaint.setStyle(Paint.Style.STROKE);
+            mInnerPaint.setColor(0xFF000000 | colors[1]);
+            mInnerPaint.setStrokeWidth(container.getResources().getDimensionPixelSize(
+                    R.dimen.focus_outline_stroke_width));
+            mInnerRadius = container.getResources().getDimensionPixelSize(
+                    R.dimen.focus_inner_outline_radius);
+        } else {
+            mPaint.setStyle(Paint.Style.FILL);
+            mRadius = container.getResources().getDimensionPixelSize(
+                    R.dimen.grid_visualization_rounding_radius);
+        }
+        mMaxAlpha = Color.alpha(colors[0]);
 
         setAlpha(0);
         mShift = 0;
-        mRadius = container.getResources().getDimensionPixelSize(
-                R.dimen.grid_visualization_rounding_radius);
     }
 
     protected void setAlpha(float alpha) {
         mAlpha = alpha;
         mPaint.setAlpha((int) (mAlpha * mMaxAlpha));
+        mInnerPaint.setAlpha((int) (mAlpha * mMaxAlpha));
     }
 
     @Override
@@ -136,6 +155,20 @@
 
         Rect newRect = getDrawRect();
         if (newRect != null) {
+            if (Flags.enableFocusOutline()) {
+                int strokeWidth = (int) mPaint.getStrokeWidth();
+                // Inset for inner outline. Stroke is drawn with half outside and half inside
+                // the view. Inset by half stroke width to move the whole stroke inside the view
+                // and avoid other views occluding it. Inset one more stroke width to leave space
+                // for outer outline.
+                newRect.inset((int) (strokeWidth * 1.5), (int) (strokeWidth * 1.5));
+                c.drawRoundRect((float) newRect.left, (float) newRect.top,
+                        (float) newRect.right, (float) newRect.bottom,
+                        mInnerRadius, mInnerRadius, mInnerPaint);
+
+                // Inset outward for drawing outer outline
+                newRect.inset(-strokeWidth, -strokeWidth);
+            }
             mDirtyRect.set(newRect);
             c.drawRoundRect((float) mDirtyRect.left, (float) mDirtyRect.top,
                     (float) mDirtyRect.right, (float) mDirtyRect.bottom,
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
index fde220c..4653bf1 100644
--- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -27,6 +27,7 @@
 public class ViewGroupFocusHelper extends FocusIndicatorHelper {
 
     private final View mContainer;
+    private static final Rect sTempRect = new Rect();
 
     public ViewGroupFocusHelper(View container) {
         super(container);
@@ -35,25 +36,37 @@
 
     @Override
     public void viewToRect(View v, Rect outRect) {
-        outRect.left = 0;
-        outRect.top = 0;
+        // Using FocusedRect here allows views to provide their custom rect for drawing outline,
+        // e.g. making the Rect bigger than the content to leave some padding between view and
+        // outline
+        v.getFocusedRect(sTempRect);
+        outRect.left = sTempRect.left;
+        outRect.top = sTempRect.top;
 
         computeLocationRelativeToContainer(v, outRect);
 
         // If a view is scaled, its position will also shift accordingly. For optimization, only
         // consider this for the last node.
-        outRect.left += (1 - v.getScaleX()) * v.getWidth() / 2;
-        outRect.top += (1 - v.getScaleY()) * v.getHeight() / 2;
+        outRect.left = (int) (outRect.left + (1 - v.getScaleX()) * sTempRect.width() / 2);
+        outRect.top = (int) (outRect.top + (1 - v.getScaleY()) * sTempRect.height() / 2);
 
-        outRect.right = outRect.left + (int) (v.getScaleX() * v.getWidth());
-        outRect.bottom = outRect.top + (int) (v.getScaleY() * v.getHeight());
+        outRect.right = outRect.left + (int) (v.getScaleX() * sTempRect.width());
+        outRect.bottom = outRect.top + (int) (v.getScaleY() * sTempRect.height());
     }
 
     private void computeLocationRelativeToContainer(View child, Rect outRect) {
-        View parent = (View) child.getParent();
+        if (child == null) {
+            return;
+        }
+
         outRect.left += child.getX();
         outRect.top += child.getY();
 
+        if (child.getParent() == null || !(child.getParent() instanceof View)) {
+            return;
+        }
+
+        View parent = (View) child.getParent();
         if (parent != mContainer) {
             if (parent instanceof PagedView) {
                 PagedView page = (PagedView) parent;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index d8388c2..441bbb5 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.slice.SliceItem;
 
@@ -53,11 +54,18 @@
     public static final int LAUNCHER_STATE_ALLAPPS = 4;
     public static final int LAUNCHER_STATE_UNCHANGED = 5;
 
+    @NonNull
+    protected final Context mContext;
+    @Nullable
+    protected final ActivityContext mActivityContext;
+
+    private KeyboardStateManager mKeyboardStateManager;
     private InstanceId mInstanceId;
 
-    protected @Nullable ActivityContext mActivityContext = null;
-    protected @Nullable Context mContext = null;
-    private KeyboardStateManager mKeyboardStateManager;
+    public StatsLogManager(@NonNull Context context) {
+        mContext = context;
+        mActivityContext = ActivityContext.lookupContextNoThrow(context);
+    }
 
     /**
      * Returns event enum based on the two state transition information when swipe
@@ -117,6 +125,9 @@
         @UiEvent(doc = "Task launched from overview using SWIPE DOWN")
         LAUNCHER_TASK_LAUNCH_SWIPE_DOWN(340),
 
+        @UiEvent(doc = "App launched by dragging and dropping, probably from taskbar")
+        LAUNCHER_APP_LAUNCH_DRAGDROP(1552),
+
         @UiEvent(doc = "TASK dismissed from overview using SWIPE UP")
         LAUNCHER_TASK_DISMISS_SWIPE_UP(341),
 
@@ -196,18 +207,29 @@
         @UiEvent(doc = "User tapped on app info system shortcut.")
         LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP(515),
 
+        /**
+         * @deprecated Use {@link #LAUNCHER_APP_ICON_MENU_SPLIT_LEFT_TOP} or
+         *             {@link #LAUNCHER_APP_ICON_MENU_SPLIT_RIGHT_BOTTOM}
+         */
+        @Deprecated
         @UiEvent(doc = "User tapped on split screen icon on a task menu.")
         LAUNCHER_SYSTEM_SHORTCUT_SPLIT_SCREEN_TAP(518),
 
         @UiEvent(doc = "User tapped on free form icon on a task menu.")
         LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP(519),
 
+        @UiEvent(doc = "User tapped on desktop icon on a task menu.")
+        LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP(1706),
+
         @UiEvent(doc = "User tapped on pause app system shortcut.")
         LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP(521),
 
         @UiEvent(doc = "User tapped on pin system shortcut.")
         LAUNCHER_SYSTEM_SHORTCUT_PIN_TAP(522),
 
+        @UiEvent(doc = "User tapped on don't suggest app system shortcut.")
+        LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP(1603),
+
         @UiEvent(doc = "User is shown All Apps education view.")
         LAUNCHER_ALL_APPS_EDU_SHOWN(523),
 
@@ -281,6 +303,12 @@
         @UiEvent(doc = "User long presses on the bottom bezel area.")
         LAUNCHER_LONG_PRESS_NAVBAR(1544),
 
+        @UiEvent(doc = "User deep presses on the stashed taskbar")
+        LAUNCHER_DEEP_PRESS_STASHED_TASKBAR(1602),
+
+        @UiEvent(doc = "User long presses on the stashed taskbar")
+        LAUNCHER_LONG_PRESS_STASHED_TASKBAR(1592),
+
         @UiEvent(doc = "User swipes or fling in UP direction from bottom bazel area.")
         LAUNCHER_HOME_GESTURE(574),
 
@@ -624,6 +652,9 @@
         @UiEvent(doc = "User tapped taskbar All Apps button.")
         LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP(1057),
 
+        @UiEvent(doc = "User long pressed taskbar All Apps button.")
+        LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS(1607),
+
         @UiEvent(doc = "User tapped on Share app system shortcut.")
         LAUNCHER_SYSTEM_SHORTCUT_APP_SHARE_TAP(1075),
 
@@ -698,6 +729,48 @@
         @UiEvent(doc = "User tapped private space settings button")
         LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP(1550),
 
+        @UiEvent(doc = "User tapped on install to private space system shortcut.")
+        LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP(1565),
+
+        @UiEvent(doc = "User tapped private space install app button.")
+        LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP(1605),
+
+        @UiEvent(doc = "User attempted to create split screen with a widget")
+        LAUNCHER_SPLIT_WIDGET_ATTEMPT(1604),
+
+        @UiEvent(doc = "User tapped on private space uninstall system shortcut.")
+        LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP(1608),
+
+        @UiEvent(doc = "User initiated split selection")
+        LAUNCHER_SPLIT_SELECTION_INITIATED(1618),
+
+        @UiEvent(doc = "User finished a split selection session")
+        LAUNCHER_SPLIT_SELECTION_COMPLETE(1619),
+
+        @UiEvent(doc = "User selected both apps for split screen")
+        LAUNCHER_SPLIT_SELECTED_SECOND_APP(1609),
+
+        @UiEvent(doc = "User exited split selection by going home via swipe, button, or state "
+                + "transition")
+        LAUNCHER_SPLIT_SELECTION_EXIT_HOME(1610),
+
+        @UiEvent(doc = "User exited split selection by tapping cancel in split instructions view")
+        LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON(1611),
+
+        @UiEvent(doc = "User exited split selection when another activity/app came to foreground"
+                + " after first app had been selected OR if user long-pressed on home. Default exit"
+                + " metric.")
+        LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED(1612),
+
+        @UiEvent(doc = "User tapped add widget button in widget sheet.")
+        LAUNCHER_WIDGET_ADD_BUTTON_TAP(1622),
+
+        @UiEvent(doc = "Number of user installed Private profile apps, shown above separator line")
+        LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT(1672),
+
+        @UiEvent(doc = "Number of preinstalled Private profile apps, shown under separator line")
+        LAUNCHER_PRIVATE_SPACE_PREINSTALLED_APPS_COUNT(1673)
+
         // ADD MORE
         ;
 
@@ -1132,10 +1205,7 @@
      * Creates a new instance of {@link StatsLogManager} based on provided context.
      */
     public static StatsLogManager newInstance(Context context) {
-        StatsLogManager manager = Overrides.getObject(StatsLogManager.class,
+        return Overrides.getObject(StatsLogManager.class,
                 context.getApplicationContext(), R.string.stats_log_manager_class);
-        manager.mActivityContext = ActivityContext.lookupContextNoThrow(context);
-        manager.mContext = context;
-        return manager;
     }
 }
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 5e86bd6..3fa6da4 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.model;
 
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
@@ -31,8 +32,9 @@
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -84,6 +86,7 @@
 
         final ArrayList<ItemInfo> addedItemsFinal = new ArrayList<>();
         final IntArray addedWorkspaceScreensFinal = new IntArray();
+        final Context context = app.getContext();
 
         synchronized (dataModel) {
             IntArray workspaceScreens = dataModel.collectWorkspaceScreens();
@@ -98,15 +101,20 @@
                     }
 
                     // b/139663018 Short-circuit this logic if the icon is a system app
-                    if (PackageManagerHelper.isSystemApp(app.getContext(),
+                    if (PackageManagerHelper.isSystemApp(context,
                             Objects.requireNonNull(item.getIntent()))) {
                         continue;
                     }
+
+                    if (item instanceof ItemInfoWithIcon
+                            && ((ItemInfoWithIcon) item).isArchived()) {
+                        continue;
+                    }
                 }
 
                 if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                     if (item instanceof WorkspaceItemFactory) {
-                        item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+                        item = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
                     }
                 }
                 if (item != null) {
@@ -115,8 +123,8 @@
             }
 
             InstallSessionHelper packageInstaller =
-                    InstallSessionHelper.INSTANCE.get(app.getContext());
-            LauncherApps launcherApps = app.getContext().getSystemService(LauncherApps.class);
+                    InstallSessionHelper.INSTANCE.get(context);
+            LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
 
             for (ItemInfo item : filteredItems) {
                 // Find appropriate space for the item.
@@ -125,11 +133,11 @@
                 int screenId = coords[0];
 
                 ItemInfo itemInfo;
-                if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
-                        item instanceof LauncherAppWidgetInfo) {
+                if (item instanceof WorkspaceItemInfo || item instanceof CollectionInfo
+                        || item instanceof LauncherAppWidgetInfo) {
                     itemInfo = item;
                 } else if (item instanceof WorkspaceItemFactory) {
-                    itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
+                    itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(context);
                 } else {
                     throw new RuntimeException("Unexpected info type");
                 }
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 190eb78..39c1243 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -38,6 +38,8 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SafeCloseable;
@@ -53,6 +55,7 @@
 /**
  * Stores the list of all applications for the all apps view.
  */
+@SuppressWarnings("NewApi")
 public class AllAppsList {
 
     private static final String TAG = "AllAppsList";
@@ -166,7 +169,7 @@
     public AppInfo addPromiseApp(
             Context context, PackageInstallInfo installInfo, boolean loadIcon) {
         // only if not yet installed
-        if (new PackageManagerHelper(context)
+        if (PackageManagerHelper.INSTANCE.get(context)
                 .isAppInstalled(installInfo.packageName, installInfo.user)) {
             return null;
         }
@@ -200,9 +203,16 @@
             if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName)
                     && appInfo.user.equals(user)) {
                 if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
-                        || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
+                        || installInfo.state == PackageInstallInfo.STATUS_INSTALLING
+                        // In case unarchival fails, we would want to keep the icon and update
+                        // back the progress to 0 for the all apps view without removing the
+                        // icon, which is contrary to what happens during normal app installation
+                        // flow.
+                        || (installInfo.state == PackageInstallInfo.STATUS_FAILED
+                                && appInfo.isArchived())) {
                     if (appInfo.isAppStartable()
-                            && installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
+                            && installInfo.state == PackageInstallInfo.STATUS_INSTALLING
+                            && !appInfo.isArchived()) {
                         continue;
                     }
                     appInfo.setProgressLevel(installInfo);
@@ -289,6 +299,8 @@
      */
     public List<LauncherActivityInfo> updatePackage(
             Context context, String packageName, UserHandle user) {
+        final ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(context);
+        final UserCache userCache = UserCache.getInstance(context);
         final List<LauncherActivityInfo> matches = context.getSystemService(LauncherApps.class)
                 .getActivityList(packageName, user);
         if (matches.size() > 0) {
@@ -316,11 +328,9 @@
 
                     mIconCache.getTitleAndIcon(applicationInfo, info, false /* useLowResIcon */);
                     applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
-                    applicationInfo.setProgressLevel(
-                            PackageManagerHelper.getLoadingProgress(info),
-                            PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
                     applicationInfo.intent = launchIntent;
-
+                    AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info,
+                            userCache.getUserInfo(user), apiWrapper);
                     mDataChanged = true;
                 }
             }
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 9b2344d..41dbe4e 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -16,36 +16,48 @@
 
 package com.android.launcher3.model;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.Flags.enableWorkspaceInflation;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
 import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.os.Process;
 import android.os.Trace;
 import android.util.Log;
+import android.util.Pair;
+import android.view.View;
+
+import androidx.annotation.NonNull;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel.CallbackTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Workspace;
+import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInflater;
 import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.LooperIdleLock;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -57,7 +69,7 @@
 /**
  * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
  */
-public abstract class BaseLauncherBinder {
+public class BaseLauncherBinder {
 
     protected static final String TAG = "LauncherBinder";
     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
@@ -73,8 +85,8 @@
     private int mMyBindingId;
 
     public BaseLauncherBinder(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacksList, LooperExecutor uiExecutor) {
-        mUiExecutor = uiExecutor;
+            AllAppsList allAppsList, Callbacks[] callbacksList) {
+        mUiExecutor = MAIN_EXECUTOR;
         mApp = app;
         mBgDataModel = dataModel;
         mBgAllAppsList = allAppsList;
@@ -150,7 +162,16 @@
     /**
      * BindDeepShortcuts is abstract because it is a no-op for the go launcher.
      */
-    public abstract void bindDeepShortcuts();
+    public void bindDeepShortcuts() {
+        if (!WIDGETS_ENABLED) {
+            return;
+        }
+        final HashMap<ComponentKey, Integer> shortcutMapCopy;
+        synchronized (mBgDataModel) {
+            shortcutMapCopy = new HashMap<>(mBgDataModel.deepShortcutMap);
+        }
+        executeCallbacksTask(c -> c.bindDeepShortcutMap(shortcutMapCopy), mUiExecutor);
+    }
 
     /**
      * Binds the all apps results from LoaderTask to the callbacks UX.
@@ -170,12 +191,24 @@
     /**
      * bindWidgets is abstract because it is a no-op for the go launcher.
      */
-    public abstract void bindWidgets();
+    public void bindWidgets() {
+        if (!WIDGETS_ENABLED) {
+            return;
+        }
+        final List<WidgetsListBaseEntry> widgets =
+                mBgDataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
+        executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
+    }
 
     /**
      * bindWidgets is abstract because it is a no-op for the go launcher.
      */
-    public abstract void bindSmartspaceWidget();
+    public void bindSmartspaceWidget() {
+        if (!WIDGETS_ENABLED) {
+            return;
+        }
+        executeCallbacksTask(c -> c.bindSmartspaceWidget(), mUiExecutor);
+    }
 
     /**
      * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
@@ -279,8 +312,8 @@
             // Separate the items that are on the current screen, and all the other remaining items
             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
-            ArrayList<LauncherAppWidgetInfo> currentAppWidgets = new ArrayList<>();
-            ArrayList<LauncherAppWidgetInfo> otherAppWidgets = new ArrayList<>();
+            ArrayList<ItemInfo> currentAppWidgets = new ArrayList<>();
+            ArrayList<ItemInfo> otherAppWidgets = new ArrayList<>();
 
             filterCurrentWorkspaceItems(currentScreenIds, mWorkspaceItems, currentWorkspaceItems,
                     otherWorkspaceItems);
@@ -303,9 +336,16 @@
             // Bind workspace screens
             executeCallbacksTask(c -> c.bindScreens(mOrderedScreenIds), mUiExecutor);
 
+            ItemInflater inflater = mCallbacks.getItemInflater();
+
             // Load items on the current page.
-            bindWorkspaceItems(currentWorkspaceItems, mUiExecutor);
-            bindAppWidgets(currentAppWidgets, mUiExecutor);
+            if (enableWorkspaceInflation() && inflater != null) {
+                inflateAsyncAndBind(currentWorkspaceItems, inflater, mUiExecutor);
+                inflateAsyncAndBind(currentAppWidgets, inflater, mUiExecutor);
+            } else {
+                bindItemsInChunks(currentWorkspaceItems, ITEMS_CHUNK, mUiExecutor);
+                bindItemsInChunks(currentAppWidgets, 1, mUiExecutor);
+            }
             if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
                 mExtraItems.forEach(item ->
                         executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
@@ -313,9 +353,39 @@
 
             RunnableList pendingTasks = new RunnableList();
             Executor pendingExecutor = pendingTasks::add;
-            bindWorkspaceItems(otherWorkspaceItems, pendingExecutor);
-            bindAppWidgets(otherAppWidgets, pendingExecutor);
 
+            RunnableList onCompleteSignal = new RunnableList();
+
+            if (enableWorkspaceInflation() && inflater != null) {
+                MODEL_EXECUTOR.execute(() ->  {
+                    inflateAsyncAndBind(otherWorkspaceItems, inflater, pendingExecutor);
+                    inflateAsyncAndBind(otherAppWidgets, inflater, pendingExecutor);
+                    setupPendingBind(currentScreenIds, pendingExecutor);
+
+                    // Wait for the async inflation to complete and then notify the completion
+                    // signal on UI thread.
+                    MAIN_EXECUTOR.execute(onCompleteSignal::executeAllAndDestroy);
+                });
+            } else {
+                bindItemsInChunks(otherWorkspaceItems, ITEMS_CHUNK, pendingExecutor);
+                bindItemsInChunks(otherAppWidgets, 1, pendingExecutor);
+                setupPendingBind(currentScreenIds, pendingExecutor);
+                onCompleteSignal.executeAllAndDestroy();
+            }
+
+            executeCallbacksTask(
+                    c -> {
+                        if (!enableWorkspaceInflation()) {
+                            MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+                        }
+                        c.onInitialBindComplete(currentScreenIds, pendingTasks, onCompleteSignal,
+                                workspaceItemCount, isBindSync);
+                    }, mUiExecutor);
+        }
+
+        private void setupPendingBind(
+                IntSet currentScreenIds,
+                Executor pendingExecutor) {
             StringCache cacheClone = mBgDataModel.stringCache.clone();
             executeCallbacksTask(c -> c.bindStringCache(cacheClone), pendingExecutor);
 
@@ -326,38 +396,39 @@
                         ItemInstallQueue.INSTANCE.get(mApp.getContext())
                                 .resumeModelPush(FLAG_LOADER_RUNNING);
                     });
-
-            executeCallbacksTask(
-                    c -> {
-                        MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                        c.onInitialBindComplete(
-                                currentScreenIds, pendingTasks, workspaceItemCount, isBindSync);
-                    }, mUiExecutor);
         }
 
-        private void bindWorkspaceItems(
-                final ArrayList<ItemInfo> workspaceItems, final Executor executor) {
+        /**
+         * Tries to inflate the items asynchronously and bind. Returns true on success or false if
+         * async-binding is not supported in this case.
+         */
+        private void inflateAsyncAndBind(
+                List<ItemInfo> items, @NonNull ItemInflater inflater, Executor executor) {
+            if (mMyBindingId != mBgDataModel.lastBindId) {
+                Log.d(TAG, "Too many consecutive reloads, skipping obsolete view inflation");
+                return;
+            }
+
+            ModelWriter writer = mApp.getModel()
+                    .getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null);
+            List<Pair<ItemInfo, View>> bindItems = items.stream().map(i ->
+                    Pair.create(i, inflater.inflateItem(i, writer, null))).toList();
+            executeCallbacksTask(c -> c.bindInflatedItems(bindItems), executor);
+        }
+
+        private void bindItemsInChunks(
+                List<ItemInfo> workspaceItems, int chunkCount, Executor executor) {
             // Bind the workspace items
             int count = workspaceItems.size();
-            for (int i = 0; i < count; i += ITEMS_CHUNK) {
+            for (int i = 0; i < count; i += chunkCount) {
                 final int start = i;
-                final int chunkSize = (i + ITEMS_CHUNK <= count) ? ITEMS_CHUNK : (count - i);
+                final int chunkSize = (i + chunkCount <= count) ? chunkCount : (count - i);
                 executeCallbacksTask(
                         c -> c.bindItems(workspaceItems.subList(start, start + chunkSize), false),
                         executor);
             }
         }
 
-        private void bindAppWidgets(List<LauncherAppWidgetInfo> appWidgets, Executor executor) {
-            // Bind the widgets, one at a time
-            int count = appWidgets.size();
-            for (int i = 0; i < count; i++) {
-                final ItemInfo widget = appWidgets.get(i);
-                executeCallbacksTask(
-                        c -> c.bindItems(Collections.singletonList(widget), false), executor);
-            }
-        }
-
         protected void executeCallbacksTask(CallbackTask task, Executor executor) {
             executor.execute(() -> {
                 if (mMyBindingId != mBgDataModel.lastBindId) {
@@ -430,8 +501,11 @@
             bindAppWidgets(appWidgets);
             executeCallbacksTask(c -> {
                 MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-                c.onInitialBindComplete(
-                        mCurrentScreenIds, new RunnableList(), workspaceItemCount, isBindSync);
+
+                RunnableList onCompleteSignal = new RunnableList();
+                onCompleteSignal.executeAllAndDestroy();
+                c.onInitialBindComplete(mCurrentScreenIds, new RunnableList(), onCompleteSignal,
+                        workspaceItemCount, isBindSync);
             }, mUiExecutor);
         }
 
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 7f0f683..d5de4ce 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -18,9 +18,9 @@
 import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY;
 
 import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN;
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
 import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
 
 import static java.util.stream.Collectors.groupingBy;
@@ -33,6 +33,8 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.Pair;
+import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -42,6 +44,8 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -54,6 +58,7 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.ItemInflater;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -99,9 +104,9 @@
     public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
 
     /**
-     * Map of id to FolderInfos of all the folders created by LauncherModel
+     * Map of id to CollectionInfos of all the folders or app pairs created by LauncherModel
      */
-    public final IntSparseArrayMap<FolderInfo> folders = new IntSparseArrayMap<>();
+    public final IntSparseArrayMap<CollectionInfo> collections = new IntSparseArrayMap<>();
 
     /**
      * Extra container based items
@@ -141,7 +146,7 @@
     public synchronized void clear() {
         workspaceItems.clear();
         appWidgets.clear();
-        folders.clear();
+        collections.clear();
         itemsIdMap.clear();
         deepShortcutMap.clear();
         extraItems.clear();
@@ -176,9 +181,9 @@
         for (int i = 0; i < appWidgets.size(); i++) {
             writer.println(prefix + '\t' + appWidgets.get(i).toString());
         }
-        writer.println(prefix + " ---- folder items ");
-        for (int i = 0; i < folders.size(); i++) {
-            writer.println(prefix + '\t' + folders.valueAt(i).toString());
+        writer.println(prefix + " ---- collection items ");
+        for (int i = 0; i < collections.size(); i++) {
+            writer.println(prefix + '\t' + collections.valueAt(i).toString());
         }
         writer.println(prefix + " ---- extra items ");
         for (int i = 0; i < extraItems.size(); i++) {
@@ -208,12 +213,12 @@
             switch (item.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                 case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
-                    folders.remove(item.id);
+                    collections.remove(item.id);
                     if (FeatureFlags.IS_STUDIO_BUILD) {
                         for (ItemInfo info : itemsIdMap) {
                             if (info.container == item.id) {
-                                // We are deleting a folder which still contains items that
-                                // think they are contained by that folder.
+                                // We are deleting a collection which still contains items that
+                                // think they are contained by that collection.
                                 String msg = "deleting a collection (" + item + ") which still "
                                         + "contains items (" + info + ")";
                                 Log.e(TAG, msg);
@@ -255,10 +260,15 @@
         itemsIdMap.put(item.id, item);
         switch (item.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-            case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
-                folders.put(item.id, (FolderInfo) item);
+                collections.put(item.id, (FolderInfo) item);
                 workspaceItems.add(item);
                 break;
+            case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
+                collections.put(item.id, (AppPairInfo) item);
+                // Fall through here. App pairs are both containers (like folders) and containable
+                // items (can be placed in folders). So we need to add app pairs to the folders
+                // array (above) but also verify the existence of their container, like regular
+                // apps (below).
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
@@ -266,14 +276,14 @@
                     workspaceItems.add(item);
                 } else {
                     if (newItem) {
-                        if (!folders.containsKey(item.container)) {
+                        if (!collections.containsKey(item.container)) {
                             // Adding an item to a nonexistent collection.
                             String msg = "attempted to add item: " + item + " to a nonexistent app"
                                     + " collection";
                             Log.e(TAG, msg);
                         }
                     } else {
-                        findOrMakeFolder(item.container).add((WorkspaceItemInfo) item, false);
+                        findOrMakeFolder(item.container).add(item);
                     }
                 }
                 break;
@@ -302,7 +312,7 @@
      * shortcuts and unpinning any extra shortcuts.
      */
     public synchronized void updateShortcutPinnedState(Context context, UserHandle user) {
-        if (GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return;
         }
 
@@ -368,15 +378,18 @@
      * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    public synchronized FolderInfo findOrMakeFolder(int id) {
+    public synchronized CollectionInfo findOrMakeFolder(int id) {
         // See if a placeholder was created for us already
-        FolderInfo folderInfo = folders.get(id);
-        if (folderInfo == null) {
-            // No placeholder -- create a new instance
-            folderInfo = new FolderInfo();
-            folders.put(id, folderInfo);
+        CollectionInfo collectionInfo = collections.get(id);
+        if (collectionInfo == null) {
+            // No placeholder -- create a new blank folder instance. At this point, we don't know
+            // if the desired container is supposed to be a folder or an app pair. In the case that
+            // it is an app pair, the blank folder will be replaced by a blank app pair when the app
+            // pair is getting processed, in WorkspaceItemProcessor.processFolderOrAppPair().
+            collectionInfo = new FolderInfo();
+            collections.put(id, collectionInfo);
         }
-        return folderInfo;
+        return collectionInfo;
     }
 
     /**
@@ -495,7 +508,15 @@
         default void clearPendingBinds() { }
         default void startBinding() { }
 
-        default void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
+        @Nullable
+        default ItemInflater getItemInflater() {
+            return null;
+        }
+
+        default void bindItems(@NonNull List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
+        /** Alternate method to bind preinflated views */
+        default void bindInflatedItems(@NonNull List<Pair<ItemInfo, View>> items) { }
+
         default void bindScreens(IntArray orderedScreenIds) { }
         default void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) { }
         default void finishBindingItems(IntSet pagesBoundFirst) { }
@@ -520,7 +541,9 @@
         default void bindSmartspaceWidget() { }
 
         /** Called when workspace has been bound. */
-        default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
+        default void onInitialBindComplete(@NonNull IntSet boundPages,
+                @NonNull RunnableList pendingTasks,
+                @NonNull RunnableList onCompleteSignal,
                 int workspaceItemCount, boolean isBindSync) {
             pendingTasks.executeAllAndDestroy();
         }
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 1360510..88ca009 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -333,7 +333,7 @@
             for (int widgetId : allWidgets) {
                 if (!validWidgets.contains(widgetId)) {
                     try {
-                        FileLog.d(TAG, "Deleting invalid widget " + widgetId);
+                        FileLog.d(TAG, "Deleting widget not found in db: appWidgetId=" + widgetId);
                         holder.deleteAppWidgetId(widgetId);
                         isAnyWidgetRemoved = true;
                     } catch (RuntimeException e) {
@@ -342,15 +342,17 @@
                 }
             }
             if (isAnyWidgetRemoved) {
-                final String allWidgetsIds = Arrays.stream(allWidgets).mapToObj(String::valueOf)
+                final String allLauncherHostWidgetIds = Arrays.stream(allWidgets)
+                        .mapToObj(String::valueOf)
                         .collect(Collectors.joining(",", "[", "]"));
-                final String validWidgetsIds = Arrays.stream(
+                final String allValidLauncherDbWidgetIds = Arrays.stream(
                                 validWidgets.getArray().toArray()).mapToObj(String::valueOf)
                         .collect(Collectors.joining(",", "[", "]"));
                 FileLog.d(TAG,
-                        "One or more widgets was removed. db_path=" + db.getPath()
-                                + " allWidgetsIds=" + allWidgetsIds
-                                + ", validWidgetsIds=" + validWidgetsIds);
+                        "One or more widgets was removed: "
+                                + " allLauncherHostWidgetIds=" + allLauncherHostWidgetIds
+                                + ", allValidLauncherDbWidgetIds=" + allValidLauncherDbWidgetIds
+                );
             }
         } finally {
             holder.destroy();
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index f24d1d2..729b381 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -53,6 +53,13 @@
     private final @DeviceType int mDeviceType;
     private final String mDbFile;
 
+    public DeviceGridState(int columns, int row, int numHotseat, int deviceType, String dbFile) {
+        mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", columns, row);
+        mNumHotseat = numHotseat;
+        mDeviceType = deviceType;
+        mDbFile = dbFile;
+    }
+
     public DeviceGridState(InvariantDeviceProfile idp) {
         mGridSizeString = String.format(Locale.ENGLISH, "%d,%d", idp.numColumns, idp.numRows);
         mNumHotseat = idp.numDatabaseHotseatIcons;
@@ -149,11 +156,11 @@
     }
 
     public Integer getColumns() {
-        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(0)));
+        return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[0]));
     }
 
     public Integer getRows() {
-        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(2)));
+        return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[1]));
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 9e91b9d..cc20cd1 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -36,6 +36,7 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -67,7 +68,8 @@
     private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
             = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
 
-    private static final String FOLDER_ITEM_EXTRA = "folderItem";
+    // String retained as "folderItem" for back-compatibility reasons.
+    private static final String COLLECTION_ITEM_EXTRA = "folderItem";
     private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
     private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
     private static final String WIDGET_ITEM_EXTRA = "widgetItem";
@@ -105,20 +107,19 @@
     @WorkerThread
     private void sendBroadcastToInstaller(Context context, String installerPackageName,
             Set<String> packages, List<ItemInfo> firstScreenItems) {
-        Set<String> folderItems = new HashSet<>();
+        Set<String> collectionItems = new HashSet<>();
         Set<String> workspaceItems = new HashSet<>();
         Set<String> hotseatItems = new HashSet<>();
         Set<String> widgetItems = new HashSet<>();
 
         for (ItemInfo info : firstScreenItems) {
-            if (info instanceof FolderInfo) {
-                FolderInfo folderInfo = (FolderInfo) info;
-                String folderItemInfoPackage;
-                for (ItemInfo folderItemInfo : cloneOnMainThread(folderInfo.contents)) {
-                    folderItemInfoPackage = getPackageName(folderItemInfo);
-                    if (folderItemInfoPackage != null
-                            && packages.contains(folderItemInfoPackage)) {
-                        folderItems.add(folderItemInfoPackage);
+            if (info instanceof CollectionInfo ci) {
+                String collectionItemInfoPackage;
+                for (ItemInfo collectionItemInfo : cloneOnMainThread(ci.getAppContents())) {
+                    collectionItemInfoPackage = getPackageName(collectionItemInfo);
+                    if (collectionItemInfoPackage != null
+                            && packages.contains(collectionItemInfoPackage)) {
+                        collectionItems.add(collectionItemInfoPackage);
                     }
                 }
             }
@@ -137,13 +138,13 @@
         }
 
         if (DEBUG) {
-            printList(installerPackageName, "Folder item", folderItems);
+            printList(installerPackageName, "Collection item", collectionItems);
             printList(installerPackageName, "Workspace item", workspaceItems);
             printList(installerPackageName, "Hotseat item", hotseatItems);
             printList(installerPackageName, "Widget item", widgetItems);
         }
 
-        if (folderItems.isEmpty()
+        if (collectionItems.isEmpty()
                 && workspaceItems.isEmpty()
                 && hotseatItems.isEmpty()
                 && widgetItems.isEmpty()) {
@@ -152,7 +153,7 @@
         }
         context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
                 .setPackage(installerPackageName)
-                .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
+                .putStringArrayListExtra(COLLECTION_ITEM_EXTRA, new ArrayList<>(collectionItems))
                 .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
                 .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
                 .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
@@ -180,7 +181,7 @@
     }
 
     /**
-     * Clone the provided list on UI thread. This is used for {@link FolderInfo#contents} which
+     * Clone the provided list on UI thread. This is used for {@link FolderInfo#getContents()} which
      * is always modified on UI thread.
      */
     @AnyThread
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index efd5574..f24a7c1 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -38,7 +38,9 @@
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
@@ -47,6 +49,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
+import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -94,6 +97,15 @@
         return needsToMigrate;
     }
 
+    @VisibleForTesting
+    public static List<DbEntry> readAllEntries(SQLiteDatabase db, String tableName,
+            Context context) {
+        DbReader dbReader = new DbReader(db, tableName, context, getValidPackages(context));
+        List<DbEntry> result = dbReader.loadAllWorkspaceEntries();
+        result.addAll(dbReader.loadHotseatEntries());
+        return result;
+    }
+
     /**
      * When migrating the grid, we copy the table
      * {@link LauncherSettings.Favorites#TABLE_NAME} from {@code source} into
@@ -105,15 +117,23 @@
      */
     public static boolean migrateGridIfNeeded(
             @NonNull Context context,
-            @NonNull InvariantDeviceProfile idp,
+            @NonNull DeviceGridState srcDeviceState,
+            @NonNull DeviceGridState destDeviceState,
             @NonNull DatabaseHelper target,
             @NonNull SQLiteDatabase source) {
-
-        DeviceGridState srcDeviceState = new DeviceGridState(context);
-        DeviceGridState destDeviceState = new DeviceGridState(idp);
         if (!needsToMigrate(srcDeviceState, destDeviceState)) {
             return true;
         }
+
+        if (Flags.enableGridMigrationFix()
+                && srcDeviceState.getColumns().equals(destDeviceState.getColumns())
+                && srcDeviceState.getRows() < destDeviceState.getRows()) {
+            // Only use this strategy when comparing the previous grid to the new grid and the
+            // columns are the same and the destination has more rows
+            copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
+            destDeviceState.writeToPrefs(context);
+            return true;
+        }
         copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
 
         HashSet<String> validPackages = getValidPackages(context);
@@ -204,19 +224,13 @@
             screens.add(screenId);
         }
 
-        boolean preservePages = false;
-        if (screens.isEmpty() && FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.get()) {
-            preservePages = destDeviceState.compareTo(srcDeviceState) >= 0
-                    && destDeviceState.getColumns() - srcDeviceState.getColumns() <= 2;
-        }
-
         // Then we place the items on the screens
         for (int screenId : screens) {
             if (DEBUG) {
                 Log.d(TAG, "Migrating " + screenId);
             }
             solveGridPlacement(helper, srcReader,
-                    destReader, screenId, trgX, trgY, workspaceToBeAdded, false);
+                    destReader, screenId, trgX, trgY, workspaceToBeAdded);
             if (workspaceToBeAdded.isEmpty()) {
                 break;
             }
@@ -226,8 +240,8 @@
         // any of the screens, in this case we add them to new screens until all of them are placed.
         int screenId = destReader.mLastScreenId + 1;
         while (!workspaceToBeAdded.isEmpty()) {
-            solveGridPlacement(helper, srcReader,
-                    destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages);
+            solveGridPlacement(helper, srcReader, destReader, screenId, trgX, trgY,
+                    workspaceToBeAdded);
             screenId++;
         }
 
@@ -262,7 +276,8 @@
             String srcTableName, String destTableName) {
         int id = copyEntryAndUpdate(helper, entry, srcTableName, destTableName);
 
-        if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+        if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+                || entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR) {
             for (Set<Integer> itemIds : entry.mFolderItems.values()) {
                 for (int itemId : itemIds) {
                     copyEntryAndUpdate(helper, itemId, id, srcTableName, destTableName);
@@ -328,7 +343,7 @@
     private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
             @NonNull final DbReader srcReader, @NonNull final DbReader destReader,
             final int screenId, final int trgX, final int trgY,
-            @NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
+            @NonNull final List<DbEntry> sortedItemsToPlace) {
         final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
         final Point trg = new Point(trgX, trgY);
         final Point next = new Point(0, screenId == 0
@@ -346,8 +361,6 @@
         Iterator<DbEntry> iterator = sortedItemsToPlace.iterator();
         while (iterator.hasNext()) {
             final DbEntry entry = iterator.next();
-            if (matchingScreenIdOnly && entry.screenId < screenId) continue;
-            if (matchingScreenIdOnly && entry.screenId > screenId) break;
             if (entry.minSpanX > trgX || entry.minSpanY > trgY) {
                 iterator.remove();
                 continue;
@@ -415,7 +428,8 @@
         }
     }
 
-    protected static class DbReader {
+    @VisibleForTesting
+    public static class DbReader {
 
         private final SQLiteDatabase mDb;
         private final String mTableName;
@@ -426,7 +440,7 @@
         private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
                 new ArrayMap<>();
 
-        DbReader(SQLiteDatabase db, String tableName, Context context,
+        public DbReader(SQLiteDatabase db, String tableName, Context context,
                 Set<String> validPackages) {
             mDb = db;
             mTableName = tableName;
@@ -655,12 +669,17 @@
         }
     }
 
-    protected static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
+    public static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
 
         private String mIntent;
         private String mProvider;
         private Map<String, Set<Integer>> mFolderItems = new HashMap<>();
 
+        /**
+         * Id of the specific widget.
+         */
+        public int appWidgetId = NO_ID;
+
         /** Comparator according to the reading order */
         @Override
         public int compareTo(DbEntry another) {
@@ -694,6 +713,18 @@
             values.put(LauncherSettings.Favorites.SPANY, spanY);
         }
 
+        @Override
+        public void writeToValues(@NonNull ContentWriter writer) {
+            super.writeToValues(writer);
+            writer.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
+        }
+
+        @Override
+        public void readFromValues(@NonNull ContentValues values) {
+            super.readFromValues(values);
+            appWidgetId = values.getAsInteger(LauncherSettings.Favorites.APPWIDGET_ID);
+        }
+
         /** This id is not used in the DB is only used while doing the migration and it identifies
          * an entry on each workspace. For example two calculator icons would have the same
          * migration id even thought they have different database ids.
@@ -704,7 +735,10 @@
                 case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
                     return getFolderMigrationId();
                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                    return mProvider;
+                    // mProvider is the app the widget belongs to and appWidgetId it's the unique
+                    // is of the widget, we need both because if you remove a widget and then add it
+                    // again, then it can change and the WidgetProvider would not know the widget.
+                    return mProvider + appWidgetId;
                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                     final String intentStr = cleanIntentString(mIntent);
                     try {
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 9a3abd4..551c2d8 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.appwidget.AppWidgetManager;
@@ -39,6 +40,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
@@ -52,6 +54,7 @@
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.PersistedItemArray;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 import java.util.HashSet;
@@ -62,7 +65,7 @@
 /**
  * Class to maintain a queue of pending items to be added to the workspace.
  */
-public class ItemInstallQueue {
+public class ItemInstallQueue implements SafeCloseable {
 
     private static final String LOG = "ItemInstallQueue";
 
@@ -96,6 +99,9 @@
         mContext = context;
     }
 
+    @Override
+    public void close() {}
+
     @WorkerThread
     private void ensureQueueLoaded() {
         Preconditions.assertWorkerThread();
@@ -276,6 +282,7 @@
             return intent;
         }
 
+        @SuppressWarnings("NewApi")
         public Pair<ItemInfo, Object> getItemInfo(Context context) {
             switch (itemType) {
                 case ITEM_TYPE_APPLICATION: {
@@ -297,6 +304,10 @@
                     } else {
                         lai = laiList.get(0);
                         si.intent = makeLaunchIntent(lai);
+                        if (Flags.enableSupportForArchiving()
+                                && lai.getActivityInfo().isArchived) {
+                            si.runtimeStatusFlags |= FLAG_ARCHIVED;
+                        }
                     }
                     LauncherAppState.getInstance(context).getIconCache()
                             .getTitleAndIcon(si, () -> lai, usePackageIcon, false);
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 4370043..b17684c 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -41,6 +41,8 @@
 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.icons.IconCache;
 import com.android.launcher3.logging.FileLog;
@@ -48,11 +50,14 @@
 import com.android.launcher3.model.data.IconRequestInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSparseArrayMap;
+import com.android.launcher3.util.UserIconInfo;
 
 import java.net.URISyntaxException;
 import java.security.InvalidParameterException;
@@ -70,6 +75,7 @@
     private final Context mContext;
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mIDP;
+    private final @Nullable LauncherRestoreEventLogger mRestoreEventLogger;
 
     private final IntArray mItemsToRemove = new IntArray();
     private final IntArray mRestoredRows = new IntArray();
@@ -107,7 +113,8 @@
     public int itemType;
     public int restoreFlag;
 
-    public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState) {
+    public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState,
+            @Nullable LauncherRestoreEventLogger restoreEventLogger) {
         super(cursor);
 
         mApp = app;
@@ -115,6 +122,7 @@
         mContext = app.getContext();
         mIconCache = app.getIconCache();
         mIDP = app.getInvariantDeviceProfile();
+        mRestoreEventLogger = restoreEventLogger;
 
         // Init column indices
         mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
@@ -348,6 +356,8 @@
         final WorkspaceItemInfo info = new WorkspaceItemInfo();
         info.user = user;
         info.intent = newIntent;
+        UserCache userCache = UserCache.getInstance(mContext);
+        UserIconInfo userIconInfo = userCache.getUserInfo(user);
 
         if (loadIcon) {
             mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
@@ -357,7 +367,8 @@
         }
 
         if (mActivityInfo != null) {
-            AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo);
+            AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo,
+                    ApiWrapper.INSTANCE.get(mContext));
         }
 
         // from the db
@@ -390,9 +401,12 @@
     /**
      * Marks the current item for removal
      */
-    public void markDeleted(String reason) {
+    public void markDeleted(String reason, @RestoreError String errorType) {
         FileLog.e(TAG, reason);
         mItemsToRemove.add(id);
+        if (mRestoreEventLogger != null) {
+            mRestoreEventLogger.logSingleFavoritesItemRestoreFailed(itemType, errorType);
+        }
     }
 
     /**
@@ -431,6 +445,9 @@
             mApp.getModel().getModelDbController().update(TABLE_NAME, values,
                     Utilities.createDbSelectionQuery(Favorites._ID, mRestoredRows), null);
         }
+        if (mRestoreEventLogger != null) {
+            mRestoreEventLogger.reportLauncherRestoreResults();
+        }
     }
 
     /**
@@ -473,8 +490,11 @@
         }
         if (checkItemPlacement(info, dataModel.isFirstPagePinnedItemEnabled)) {
             dataModel.addItem(mContext, info, false, logger);
+            if (mRestoreEventLogger != null) {
+                mRestoreEventLogger.logSingleFavoritesItemRestored(itemType);
+            }
         } else {
-            markDeleted("Item position overlap");
+            markDeleted("Item position overlap", RestoreError.INVALID_LOCATION);
         }
     }
 
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a98ec64..77bc32e 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -17,8 +17,9 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
+import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
+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.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
@@ -28,16 +29,11 @@
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
-import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
 
-import android.annotation.SuppressLint;
 import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -47,12 +43,10 @@
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
-import android.graphics.Point;
 import android.os.Bundle;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -60,15 +54,15 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
-import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 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.folder.Folder;
 import com.android.launcher3.folder.FolderGridOrganizer;
@@ -82,19 +76,20 @@
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.IconRequestInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.qsb.QsbContainerView;
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IOUtils;
 import com.android.launcher3.util.IntArray;
@@ -103,16 +98,14 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.WidgetManagerHelper;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
+import com.android.launcher3.widget.WidgetInflater;
 
 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.Objects;
 import java.util.Set;
 import java.util.concurrent.CancellationException;
 
@@ -123,6 +116,7 @@
  *   - all apps icons
  *   - deep shortcuts within apps
  */
+@SuppressWarnings("NewApi")
 public class LoaderTask implements Runnable {
     private static final String TAG = "LoaderTask";
     public static final String SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen";
@@ -134,23 +128,25 @@
     private final AllAppsList mBgAllAppsList;
     protected final BgDataModel mBgDataModel;
     private final ModelDelegate mModelDelegate;
+    private boolean mIsRestoreFromBackup;
 
     private FirstScreenBroadcast mFirstScreenBroadcast;
 
     @NonNull
-    private final LauncherBinder mLauncherBinder;
+    private final BaseLauncherBinder mLauncherBinder;
 
     private final LauncherApps mLauncherApps;
     private final UserManager mUserManager;
     private final UserCache mUserCache;
+    private final PackageManagerHelper mPmHelper;
 
     private final InstallSessionHelper mSessionHelper;
     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;
 
     private boolean mStopped;
 
@@ -159,26 +155,27 @@
     private String mDbName;
 
     public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
-            ModelDelegate modelDelegate, @NonNull LauncherBinder launcherBinder) {
+            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 LauncherBinder launcherBinder,
+            ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder,
             UserManagerState userManagerState) {
         mApp = app;
         mBgAllAppsList = bgAllAppsList;
         mBgDataModel = bgModel;
         mModelDelegate = modelDelegate;
         mLauncherBinder = launcherBinder;
-
         mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
         mUserManager = mApp.getContext().getSystemService(UserManager.class);
-        mUserCache = UserCache.getInstance(mApp.getContext());
+        mUserCache = UserCache.INSTANCE.get(mApp.getContext());
+        mPmHelper = PackageManagerHelper.INSTANCE.get(mApp.getContext());
         mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
         mIconCache = mApp.getIconCache();
         mUserManagerState = userManagerState;
+        mInstallingPkgsCached = null;
     }
 
     protected synchronized void waitForIdle() {
@@ -221,17 +218,26 @@
 
         TraceHelper.INSTANCE.beginSection(TAG);
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
+        mIsRestoreFromBackup =
+                (Boolean) LauncherPrefs.get(mApp.getContext()).get(IS_FIRST_LOAD_AFTER_RESTORE);
+        LauncherRestoreEventLogger restoreEventLogger = null;
+        if (enableLauncherBrMetricsFixed()) {
+            restoreEventLogger = LauncherRestoreEventLogger.Companion
+                    .newInstance(mApp.getContext());
+        }
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
+
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
-            loadWorkspace(allShortcuts, "", memoryLogger);
+            loadWorkspace(allShortcuts, "", 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
             // from the main db as defined in the invariant device profile.
             // (e.g. both grid preview and minimal device mode uses a different db)
-            if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
+            if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
                 verifyNotStopped();
                 sanitizeFolders(mItemsDeleted);
+                sanitizeAppPairs();
                 sanitizeWidgetsShortcutsAndPackages();
                 logASplit("sanitizeData");
             }
@@ -254,7 +260,7 @@
             Trace.beginSection("LoadAllApps");
             List<LauncherActivityInfo> allActivityList;
             try {
-               allActivityList = loadAllApps();
+                allActivityList = loadAllApps();
             } finally {
                 Trace.endSection();
             }
@@ -314,8 +320,8 @@
             mLauncherBinder.bindWidgets();
             logASplit("bindWidgets");
             verifyNotStopped();
-
             LauncherPrefs prefs = LauncherPrefs.get(mApp.getContext());
+
             if (SMARTSPACE_AS_A_WIDGET.get() && prefs.get(SHOULD_SHOW_SMARTSPACE)) {
                 mLauncherBinder.bindSmartspaceWidget();
                 // Turn off pref.
@@ -349,6 +355,13 @@
             mModelDelegate.modelLoadComplete();
             transaction.commit();
             memoryLogger.clearLogs();
+            if (mIsRestoreFromBackup) {
+                mIsRestoreFromBackup = false;
+                LauncherPrefs.get(mApp.getContext()).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(false));
+                if (restoreEventLogger != null) {
+                    restoreEventLogger.reportLauncherRestoreResults();
+                }
+            }
         } catch (CancellationException e) {
             // Loader stopped, ignore
             logASplit("Cancelled");
@@ -367,10 +380,12 @@
     protected void loadWorkspace(
             List<ShortcutInfo> allDeepShortcuts,
             String selection,
-            LoaderMemoryLogger memoryLogger) {
+            LoaderMemoryLogger memoryLogger,
+            @Nullable LauncherRestoreEventLogger restoreEventLogger
+    ) {
         Trace.beginSection("LoadWorkspace");
         try {
-            loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger);
+            loadWorkspaceImpl(allDeepShortcuts, selection, memoryLogger, restoreEventLogger);
         } finally {
             Trace.endSection();
         }
@@ -391,15 +406,14 @@
     private void loadWorkspaceImpl(
             List<ShortcutInfo> allDeepShortcuts,
             String selection,
-            @Nullable LoaderMemoryLogger memoryLogger) {
+            @Nullable LoaderMemoryLogger memoryLogger,
+            @Nullable LauncherRestoreEventLogger restoreEventLogger) {
         final Context context = mApp.getContext();
-        final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
-        final boolean isSafeMode = pmHelper.isSafeMode();
         final boolean isSdCardReady = Utilities.isBootCompleted();
-        final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
+        final WidgetInflater widgetInflater = new WidgetInflater(context);
 
         ModelDbController dbController = mApp.getModel().getModelDbController();
-        dbController.tryMigrateDB();
+        dbController.tryMigrateDB(restoreEventLogger);
         Log.d(TAG, "loadWorkspace: loading default favorites");
         dbController.loadDefaultFavoritesIfNecessary();
 
@@ -409,58 +423,36 @@
 
             final HashMap<PackageUserKey, SessionInfo> installingPkgs =
                     mSessionHelper.getActiveSessions();
+            if (Flags.enableSupportForArchiving()) {
+                mInstallingPkgsCached = installingPkgs;
+            }
             installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
             FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
                     + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
 
-            final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
             mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
 
             mShortcutKeyToPinnedShortcuts = new HashMap<>();
             final LoaderCursor c = new LoaderCursor(
                     dbController.query(TABLE_NAME, null, selection, null, null),
-                    mApp, mUserManagerState);
+                    mApp, 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<>();
-
-                mUserManagerState.init(mUserCache, mUserManager);
-
-                for (UserHandle user : mUserCache.getUserProfiles()) {
-                    long serialNo = mUserCache.getSerialNumberForUser(user);
-                    boolean userUnlocked = mUserManager.isUserUnlocked(user);
-
-                    // We can only query for shortcuts when the user is unlocked.
-                    if (userUnlocked) {
-                        QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
-                                .query(ShortcutRequest.PINNED);
-                        if (pinnedShortcuts.wasSuccess()) {
-                            for (ShortcutInfo shortcut : pinnedShortcuts) {
-                                mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
-                                        shortcut);
-                            }
-                            if (pinnedShortcuts.isEmpty()) {
-                                FileLog.d(TAG, "No pinned shortcuts found for user " + user);
-                            }
-                        } else {
-                            // Shortcut manager can fail due to some race condition when the
-                            // lock state changes too frequently. For the purpose of the loading
-                            // shortcuts, consider the user is still locked.
-                            FileLog.d(TAG, "Shortcut request failed for user "
-                                    + user + ", user may still be locked.");
-                            userUnlocked = false;
-                        }
-                    }
-                    unlockedUsers.put(serialNo, userUnlocked);
-                }
+                queryPinnedShortcutsForUnlockedUsers(context, unlockedUsers);
 
                 List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
 
+                WorkspaceItemProcessor itemProcessor = new WorkspaceItemProcessor(c, memoryLogger,
+                        mUserCache, mUserManagerState, mLauncherApps, mPendingPackages,
+                        mShortcutKeyToPinnedShortcuts, mApp, mBgDataModel,
+                        mWidgetProvidersMap, installingPkgs, isSdCardReady,
+                        widgetInflater, mPmHelper, iconRequestInfos, unlockedUsers,
+                        allDeepShortcuts);
+
                 while (!mStopped && c.moveToNext()) {
-                    processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
-                            tempPackageKey, widgetHelper, pmHelper,
-                            iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
+                    itemProcessor.processItem();
                 }
                 tryLoadWorkspaceIconsInBulk(iconRequestInfos);
             } finally {
@@ -485,434 +477,106 @@
             // Remove dead items
             mItemsDeleted = c.commitDeleted();
 
-            // Sort the folder items, update ranks, and make sure all preview items are high res.
-            List<FolderGridOrganizer> verifiers =
-                    mApp.getInvariantDeviceProfile().supportedProfiles.stream().map(
-                            FolderGridOrganizer::new).toList();
-            for (FolderInfo folder : mBgDataModel.folders) {
-                Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
-                verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
-                int size = folder.contents.size();
-
-                // Update ranks here to ensure there are no gaps caused by removed folder items.
-                // Ranks are the source of truth for folder items, so cellX and cellY can be
-                // ignored for now. Database will be updated once user manually modifies folder.
-                for (int rank = 0; rank < size; ++rank) {
-                    WorkspaceItemInfo info = folder.contents.get(rank);
-                    // rank is used differently in app pairs, so don't reset
-                    if (folder.itemType != ITEM_TYPE_APP_PAIR) {
-                        info.rank = rank;
-                    }
-
-                    if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
-                            && verifiers.stream().anyMatch(
-                                verifier -> verifier.isItemInPreview(info.rank))) {
-                        mIconCache.getTitleAndIcon(info, false);
-                    }
-                }
-            }
+            processFolderItems();
+            processAppPairItems();
 
             c.commitRestoredItems();
         }
     }
 
-    private void processWorkspaceItem(LoaderCursor c,
-            LoaderMemoryLogger memoryLogger,
-            HashMap<PackageUserKey, SessionInfo> installingPkgs,
-            boolean isSdCardReady,
-            PackageUserKey tempPackageKey,
-            WidgetManagerHelper widgetHelper,
-            PackageManagerHelper pmHelper,
-            List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
-            LongSparseArray<Boolean> unlockedUsers,
-            boolean isSafeMode,
-            List<ShortcutInfo> allDeepShortcuts) {
-
-        try {
-            if (c.user == null) {
-                // User has been deleted, remove the item.
-                c.markDeleted("User has been deleted");
-                return;
+    /**
+     * After all items have been processed and added to the BgDataModel, this method sorts and
+     * requests high-res icons for the items that are part of an app pair.
+     */
+    private void processAppPairItems() {
+        for (CollectionInfo collection : mBgDataModel.collections) {
+            if (!(collection instanceof AppPairInfo appPair)) {
+                continue;
             }
 
-            boolean allowMissingTarget = false;
-            switch (c.itemType) {
-                case Favorites.ITEM_TYPE_APPLICATION:
-                case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                    Intent intent = c.parseIntent();
-                    if (intent == null) {
-                        c.markDeleted("Invalid or null intent");
-                        return;
+            appPair.getContents().sort(Folder.ITEM_POS_COMPARATOR);
+            appPair.fetchHiResIconsIfNeeded(mIconCache);
+        }
+    }
+
+    /**
+     * Initialized the UserManagerState, and determines which users are unlocked. Additionally, if
+     * the user is unlocked, it queries LauncherAppsService for pinned shortcuts and stores the
+     * result in a class variable to be used in other methods while processing workspace items.
+     *
+     * @param context used to query LauncherAppsService
+     * @param unlockedUsers this param is changed, and the updated value is used outside this method
+     */
+    @WorkerThread
+    private void queryPinnedShortcutsForUnlockedUsers(Context context,
+            LongSparseArray<Boolean> unlockedUsers) {
+        mUserManagerState.init(mUserCache, mUserManager);
+
+        for (UserHandle user : mUserCache.getUserProfiles()) {
+            long serialNo = mUserCache.getSerialNumberForUser(user);
+            boolean userUnlocked = mUserManager.isUserUnlocked(user);
+
+            // We can only query for shortcuts when the user is unlocked.
+            if (userUnlocked) {
+                QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
+                        .query(ShortcutRequest.PINNED);
+                if (pinnedShortcuts.wasSuccess()) {
+                    for (ShortcutInfo shortcut : pinnedShortcuts) {
+                        mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
+                                shortcut);
                     }
-
-                    int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
-                            ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
-                    ComponentName cn = intent.getComponent();
-                    String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
-
-                    if (TextUtils.isEmpty(targetPkg)) {
-                        c.markDeleted("Shortcuts can't have null package");
-                        return;
+                    if (pinnedShortcuts.isEmpty()) {
+                        FileLog.d(TAG, "No pinned shortcuts found for user " + user);
                     }
-
-                    // If there is no target package, it's an implicit intent
-                    // (legacy shortcut) which is always valid
-                    boolean validTarget = TextUtils.isEmpty(targetPkg)
-                            || mLauncherApps.isPackageEnabled(targetPkg, c.user);
-
-                    // If it's a deep shortcut, we'll use pinned shortcuts to restore it
-                    if (cn != null && validTarget && c.itemType
-                            != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                        // If the apk is present and the shortcut points to a specific component.
-
-                        // If the component is already present
-                        if (mLauncherApps.isActivityEnabled(cn, c.user)) {
-                            // no special handling necessary for this item
-                            c.markRestored();
-                        } else {
-                            // Gracefully try to find a fallback activity.
-                            intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
-                            if (intent != null) {
-                                c.restoreFlag = 0;
-                                c.updater().put(
-                                        Favorites.INTENT,
-                                        intent.toUri(0)).commit();
-                                cn = intent.getComponent();
-                            } else {
-                                c.markDeleted("Unable to find a launch target");
-                                return;
-                            }
-                        }
-                    }
-                    // else if cn == null => can't infer much, leave it
-                    // else if !validPkg => could be restored icon or missing sd-card
-
-                    if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
-                        // Points to a valid app (superset of cn != null) but the apk
-                        // is not available.
-
-                        if (c.restoreFlag != 0) {
-                            // Package is not yet available but might be
-                            // installed later.
-                            FileLog.d(TAG, "package not yet restored: " + targetPkg);
-                            tempPackageKey.update(targetPkg, c.user);
-                            if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
-                                // Restore has started once.
-                            } else if (installingPkgs.containsKey(tempPackageKey)) {
-                                // App restore has started. Update the flag
-                                c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
-                                FileLog.d(TAG, "restore started for installing app: " + targetPkg);
-                                c.updater().put(Favorites.RESTORED, c.restoreFlag).commit();
-                            } else {
-                                c.markDeleted("removing app that is not restored and not "
-                                        + "installing. package: " + targetPkg);
-                                return;
-                            }
-                        } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
-                            // Package is present but not available.
-                            disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
-                            // Add the icon on the workspace anyway.
-                            allowMissingTarget = true;
-                        } else if (!isSdCardReady) {
-                            // SdCard is not ready yet. Package might get available,
-                            // once it is ready.
-                            Log.d(TAG, "Missing package, will check later: " + targetPkg);
-                            mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
-                            // Add the icon on the workspace anyway.
-                            allowMissingTarget = true;
-                        } else {
-                            // Do not wait for external media load anymore.
-                            c.markDeleted("Invalid package removed: " + targetPkg);
-                            return;
-                        }
-                    }
-
-                    if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
-                        validTarget = false;
-                    }
-
-                    if (validTarget) {
-                        // The shortcut points to a valid target (either no target
-                        // or something which is ready to be used)
-                        c.markRestored();
-                    }
-
-                    boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
-
-                    WorkspaceItemInfo info;
-                    if (c.restoreFlag != 0) {
-                        // Already verified above that user is same as default user
-                        info = c.getRestoredItemInfo(intent);
-                    } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) {
-                        info = c.getAppShortcutInfo(
-                                intent, allowMissingTarget, useLowResIcon, false);
-                    } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                        ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
-                        if (unlockedUsers.get(c.serialNumber)) {
-                            ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
-                            if (pinnedShortcut == null) {
-                                // The shortcut is no longer valid.
-                                c.markDeleted("Pinned shortcut not found for package: "
-                                        + key.getPackageName());
-                                return;
-                            }
-                            info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
-                            // If the pinned deep shortcut is no longer published,
-                            // use the last saved icon instead of the default.
-                            mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
-
-                            if (pmHelper.isAppSuspended(
-                                    pinnedShortcut.getPackage(), info.user)) {
-                                info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
-                            }
-                            intent = info.getIntent();
-                            allDeepShortcuts.add(pinnedShortcut);
-                        } else {
-                            // Create a shortcut info in disabled mode for now.
-                            info = c.loadSimpleWorkspaceItem();
-                            info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
-                        }
-                    } else { // item type == ITEM_TYPE_SHORTCUT
-                        info = c.loadSimpleWorkspaceItem();
-
-                        // Shortcuts are only available on the primary profile
-                        if (!TextUtils.isEmpty(targetPkg)
-                                && pmHelper.isAppSuspended(targetPkg, c.user)) {
-                            disabledState |= FLAG_DISABLED_SUSPENDED;
-                        }
-                        info.options = c.getOptions();
-
-                        // App shortcuts that used to be automatically added to Launcher
-                        // didn't always have the correct intent flags set, so do that here
-                        if (intent.getAction() != null
-                                && intent.getCategories() != null
-                                && intent.getAction().equals(Intent.ACTION_MAIN)
-                                && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
-                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                        }
-                    }
-
-                    if (info != null) {
-                        if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                            // Skip deep shortcuts; their title and icons have already been
-                            // loaded above.
-                            iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
-                        }
-
-                        c.applyCommonProperties(info);
-
-                        info.intent = intent;
-                        info.rank = c.getRank();
-                        info.spanX = 1;
-                        info.spanY = 1;
-                        info.runtimeStatusFlags |= disabledState;
-                        if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) {
-                            info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
-                        }
-                        LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
-                        if (activityInfo != null) {
-                            info.setProgressLevel(
-                                    PackageManagerHelper.getLoadingProgress(activityInfo),
-                                    PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
-                        }
-
-                        if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
-                            tempPackageKey.update(targetPkg, c.user);
-                            SessionInfo si = installingPkgs.get(tempPackageKey);
-                            if (si == null) {
-                                info.runtimeStatusFlags
-                                        &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                            } else if (activityInfo == null) {
-                                int installProgress = (int) (si.getProgress() * 100);
-
-                                info.setProgressLevel(installProgress,
-                                        PackageInstallInfo.STATUS_INSTALLING);
-                            }
-                        }
-
-                        c.checkAndAddItem(info, mBgDataModel, memoryLogger);
-                    } else {
-                        throw new RuntimeException("Unexpected null WorkspaceItemInfo");
-                    }
-                    break;
-
-                case Favorites.ITEM_TYPE_FOLDER:
-                case Favorites.ITEM_TYPE_APP_PAIR:
-                    FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
-                    c.applyCommonProperties(folderInfo);
-
-                    folderInfo.itemType = c.itemType;
-                    // Do not trim the folder label, as is was set by the user.
-                    folderInfo.title = c.getString(c.mTitleIndex);
-                    folderInfo.spanX = 1;
-                    folderInfo.spanY = 1;
-                    folderInfo.options = c.getOptions();
-
-                    // no special handling required for restored folders
-                    c.markRestored();
-
-                    c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
-                    break;
-
-                case Favorites.ITEM_TYPE_APPWIDGET:
-                    if (WidgetsModel.GO_DISABLE_WIDGETS) {
-                        c.markDeleted("Only legacy shortcuts can have null package");
-                        return;
-                    }
-                    // Follow through
-                case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
-                    // Read all Launcher-specific widget details
-                    boolean customWidget = c.itemType
-                            == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
-                    int appWidgetId = c.getAppWidgetId();
-                    String savedProvider = c.getAppWidgetProvider();
-                    final ComponentName component;
-
-                    if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) {
-                        component  = QsbContainerView.getSearchComponentName(mApp.getContext());
-                        if (component == null) {
-                            c.markDeleted("Discarding SearchWidget without packagename ");
-                            return;
-                        }
-                    } else {
-                        component = ComponentName.unflattenFromString(savedProvider);
-                    }
-                    final boolean isIdValid =
-                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
-                    final boolean wasProviderReady =
-                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
-                    ComponentKey providerKey = new ComponentKey(component, c.user);
-                    if (!mWidgetProvidersMap.containsKey(providerKey)) {
-                        if (customWidget) {
-                            mWidgetProvidersMap.put(providerKey, CustomWidgetManager.INSTANCE
-                                    .get(mApp.getContext()).getWidgetProvider(component));
-                        } else {
-                            mWidgetProvidersMap.put(providerKey,
-                                    widgetHelper.findProvider(component, c.user));
-                        }
-                    }
-                    final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey);
-
-                    final boolean isProviderReady = isValidProvider(provider);
-                    if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
-                        c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
-                    } else {
-                        LauncherAppWidgetInfo appWidgetInfo;
-                        if (isProviderReady) {
-                            appWidgetInfo =
-                                    new LauncherAppWidgetInfo(appWidgetId, provider.provider);
-
-                            // The provider is available. So the widget is either
-                            // available or not available. We do not need to track
-                            // any future restore updates.
-                            int status = c.restoreFlag
-                                    & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
-                                    & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
-                            if (!wasProviderReady) {
-                                // If provider was not previously ready, update status and UI flag.
-
-                                // Id would be valid only if the widget restore broadcast received.
-                                if (isIdValid) {
-                                    status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-                                }
-                            }
-                            appWidgetInfo.restoreStatus = status;
-                        } else {
-                            Log.v(TAG, "Widget restore pending id=" + c.id
-                                    + " appWidgetId=" + appWidgetId
-                                    + " status=" + c.restoreFlag);
-                            appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
-                            appWidgetInfo.restoreStatus = c.restoreFlag;
-
-                            tempPackageKey.update(component.getPackageName(), c.user);
-                            SessionInfo si = installingPkgs.get(tempPackageKey);
-                            Integer installProgress = si == null
-                                    ? null
-                                    : (int) (si.getProgress() * 100);
-
-                            if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
-                                // Restore has started once.
-                            } else if (installProgress != null) {
-                                // App restore has started. Update the flag
-                                appWidgetInfo.restoreStatus
-                                        |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
-                            } else if (!isSafeMode) {
-                                c.markDeleted("Unrestored widget removed: " + component);
-                                return;
-                            }
-
-                            appWidgetInfo.installProgress =
-                                    installProgress == null ? 0 : installProgress;
-                        }
-                        if (appWidgetInfo.hasRestoreFlag(
-                                LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
-                            appWidgetInfo.bindOptions = c.parseIntent();
-                        }
-
-                        c.applyCommonProperties(appWidgetInfo);
-                        appWidgetInfo.spanX = c.getSpanX();
-                        appWidgetInfo.spanY = c.getSpanY();
-                        appWidgetInfo.options = c.getOptions();
-                        appWidgetInfo.user = c.user;
-                        appWidgetInfo.sourceContainer = c.getAppWidgetSource();
-
-                        if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
-                            c.markDeleted("Widget has invalid size: "
-                                    + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
-                            return;
-                        }
-                        LauncherAppWidgetProviderInfo widgetProviderInfo =
-                                widgetHelper.getLauncherAppWidgetInfo(appWidgetId,
-                                        appWidgetInfo.getTargetComponent());
-                        if (widgetProviderInfo != null
-                                && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
-                                || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
-                            FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
-                                    + " minSizes not meet: span=" + appWidgetInfo.spanX
-                                    + "x" + appWidgetInfo.spanY + " minSpan="
-                                    + widgetProviderInfo.minSpanX + "x"
-                                    + widgetProviderInfo.minSpanY);
-                            logWidgetInfo(mApp.getInvariantDeviceProfile(),
-                                    widgetProviderInfo);
-                        }
-                        if (!c.isOnWorkspaceOrHotseat()) {
-                            c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
-                                    + "nor CONTAINER_HOTSEAT - ignoring!");
-                            return;
-                        }
-
-                        if (!customWidget) {
-                            String providerName = appWidgetInfo.providerName.flattenToString();
-                            if (!providerName.equals(savedProvider)
-                                    || (appWidgetInfo.restoreStatus != c.restoreFlag)) {
-                                c.updater()
-                                        .put(Favorites.APPWIDGET_PROVIDER,
-                                                providerName)
-                                        .put(Favorites.RESTORED,
-                                                appWidgetInfo.restoreStatus)
-                                        .commit();
-                            }
-                        }
-
-                        if (appWidgetInfo.restoreStatus
-                                != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
-                            appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
-                                    mApp.getContext(),
-                                    appWidgetInfo.providerName,
-                                    appWidgetInfo.user);
-                            mIconCache.getTitleAndIconForApp(
-                                    appWidgetInfo.pendingItemInfo, false);
-                        }
-
-                        c.checkAndAddItem(appWidgetInfo, mBgDataModel);
-                    }
-                    break;
+                } else {
+                    // Shortcut manager can fail due to some race condition when the
+                    // lock state changes too frequently. For the purpose of the loading
+                    // shortcuts, consider the user is still locked.
+                    FileLog.d(TAG, "Shortcut request failed for user "
+                            + user + ", user may still be locked.");
+                    userUnlocked = false;
+                }
             }
-        } catch (Exception e) {
-            Log.e(TAG, "Desktop items loading interrupted", e);
+            unlockedUsers.put(serialNo, userUnlocked);
+        }
+
+    }
+
+    /**
+     * After all items have been processed and added to the BgDataModel, this method can correctly
+     * rank items inside folders and load the correct miniature preview icons to be shown when the
+     * folder is collapsed.
+     */
+    @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
+                .stream().map(FolderGridOrganizer::new).toList();
+        for (CollectionInfo collection : mBgDataModel.collections) {
+            if (!(collection instanceof FolderInfo folder)) {
+                continue;
+            }
+
+            folder.getContents().sort(Folder.ITEM_POS_COMPARATOR);
+            verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
+            int size = folder.getContents().size();
+
+            // Update ranks here to ensure there are no gaps caused by removed folder items.
+            // Ranks are the source of truth for folder items, so cellX and cellY can be
+            // ignored for now. Database will be updated once user manually modifies folder.
+            for (int rank = 0; rank < size; ++rank) {
+                ItemInfo info = folder.getContents().get(rank);
+                info.rank = rank;
+
+                if (info instanceof WorkspaceItemInfo wii
+                        && wii.usingLowResIcon()
+                        && wii.itemType == Favorites.ITEM_TYPE_APPLICATION
+                        && verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
+                    mIconCache.getTitleAndIcon(wii, false);
+                } else if (info instanceof AppPairInfo api) {
+                    api.fetchHiResIconsIfNeeded(mIconCache);
+                }
+            }
         }
     }
 
@@ -959,14 +623,32 @@
             IntArray deletedFolderIds = mApp.getModel().getModelDbController().deleteEmptyFolders();
             synchronized (mBgDataModel) {
                 for (int folderId : deletedFolderIds) {
-                    mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
-                    mBgDataModel.folders.remove(folderId);
+                    mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(folderId));
+                    mBgDataModel.collections.remove(folderId);
                     mBgDataModel.itemsIdMap.remove(folderId);
                 }
             }
         }
     }
 
+    /** 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 deleted = new IntArray();
+        deleted.addAll(deletedAppPairIds);
+        deleted.addAll(deletedAppIds);
+
+        synchronized (mBgDataModel) {
+            for (int id : deleted) {
+                mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(id));
+                mBgDataModel.collections.remove(id);
+                mBgDataModel.itemsIdMap.remove(id);
+            }
+        }
+    }
+
     private void sanitizeWidgetsShortcutsAndPackages() {
         Context context = mApp.getContext();
 
@@ -1014,7 +696,22 @@
             // Create the ApplicationInfos
             for (int i = 0; i < apps.size(); i++) {
                 LauncherActivityInfo app = apps.get(i);
-                AppInfo appInfo = new AppInfo(app, user, quietMode);
+                AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user),
+                        ApiWrapper.INSTANCE.get(mApp.getContext()), 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.
+                    String appPackageName = app.getApplicationInfo().packageName;
+                    SessionInfo si = mInstallingPkgsCached != null ? mInstallingPkgsCached.get(
+                            new PackageUserKey(appPackageName, user))
+                            : mSessionHelper.getActiveSessionInfo(user,
+                                    appPackageName);
+                    if (si != null) {
+                        appInfo.runtimeStatusFlags |= FLAG_INSTALL_SESSION_ACTIVE;
+                        appInfo.setProgressLevel((int) (si.getProgress() * 100),
+                                PackageInstallInfo.STATUS_INSTALLING);
+                    }
+                }
 
                 iconRequestInfos.add(new IconRequestInfo<>(
                         appInfo, app, /* useLowResIcon= */ false));
@@ -1088,16 +785,16 @@
 
     private void loadFolderNames() {
         FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
-                mBgAllAppsList.data, mBgDataModel.folders);
+                mBgAllAppsList.data, mBgDataModel.collections);
 
         synchronized (mBgDataModel) {
-            for (int i = 0; i < mBgDataModel.folders.size(); i++) {
+            for (int i = 0; i < mBgDataModel.collections.size(); i++) {
                 FolderNameInfos suggestionInfos = new FolderNameInfos();
-                FolderInfo info = mBgDataModel.folders.valueAt(i);
-                if (info.suggestedFolderNames == null) {
-                    provider.getSuggestedFolderName(mApp.getContext(), info.contents,
+                CollectionInfo info = mBgDataModel.collections.valueAt(i);
+                if (info instanceof FolderInfo fi && fi.suggestedFolderNames == null) {
+                    provider.getSuggestedFolderName(mApp.getContext(), fi.getAppContents(),
                             suggestionInfos);
-                    info.suggestedFolderNames = suggestionInfos;
+                    fi.suggestedFolderNames = suggestionInfos;
                 }
             }
         }
@@ -1108,52 +805,6 @@
                 && (provider.provider.getPackageName() != null);
     }
 
-    @SuppressLint("NewApi") // Already added API check.
-    private static void logWidgetInfo(InvariantDeviceProfile idp,
-            LauncherAppWidgetProviderInfo widgetProviderInfo) {
-        Point cellSize = new Point();
-        for (DeviceProfile deviceProfile : idp.supportedProfiles) {
-            deviceProfile.getCellSize(cellSize);
-            FileLog.d(TAG, "DeviceProfile available width: " + deviceProfile.availableWidthPx
-                    + ", available height: " + deviceProfile.availableHeightPx
-                    + ", cellLayoutBorderSpacePx Horizontal: "
-                    + deviceProfile.cellLayoutBorderSpacePx.x
-                    + ", cellLayoutBorderSpacePx Vertical: "
-                    + deviceProfile.cellLayoutBorderSpacePx.y
-                    + ", cellSize: " + cellSize);
-        }
-
-        StringBuilder widgetDimension = new StringBuilder();
-        widgetDimension.append("Widget dimensions:\n")
-                .append("minResizeWidth: ")
-                .append(widgetProviderInfo.minResizeWidth)
-                .append("\n")
-                .append("minResizeHeight: ")
-                .append(widgetProviderInfo.minResizeHeight)
-                .append("\n")
-                .append("defaultWidth: ")
-                .append(widgetProviderInfo.minWidth)
-                .append("\n")
-                .append("defaultHeight: ")
-                .append(widgetProviderInfo.minHeight)
-                .append("\n");
-        if (Utilities.ATLEAST_S) {
-            widgetDimension.append("targetCellWidth: ")
-                    .append(widgetProviderInfo.targetCellWidth)
-                    .append("\n")
-                    .append("targetCellHeight: ")
-                    .append(widgetProviderInfo.targetCellHeight)
-                    .append("\n")
-                    .append("maxResizeWidth: ")
-                    .append(widgetProviderInfo.maxResizeWidth)
-                    .append("\n")
-                    .append("maxResizeHeight: ")
-                    .append(widgetProviderInfo.maxResizeHeight)
-                    .append("\n");
-        }
-        FileLog.d(TAG, widgetDimension.toString());
-    }
-
     private static void logASplit(String label) {
         if (DEBUG) {
             Log.d(TAG, label);
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index d2b7161..7e1d40d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -15,10 +15,15 @@
  */
 package com.android.launcher3.model;
 
+import static android.provider.BaseColumns._ID;
 import static android.util.Base64.NO_PADDING;
 import static android.util.Base64.NO_WRAP;
 
 import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
+import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
@@ -48,6 +53,7 @@
 import android.util.Log;
 import android.util.Xml;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.AutoInstallsLayout;
@@ -62,6 +68,8 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils;
@@ -261,8 +269,12 @@
     /**
      * Migrates the DB if needed. If the migration failed, it clears the DB.
      */
-    public void tryMigrateDB() {
+    public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
+
         if (!migrateGridIfNeeded()) {
+            if (restoreEventLogger != null) {
+                sendMetricsForFailedMigration(restoreEventLogger, getDb());
+            }
             FileLog.d(TAG, "Migration failed: resetting launcher database");
             createEmptyDB();
             LauncherPrefs.get(mContext).putSync(
@@ -300,8 +312,12 @@
         mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper
                 : createDatabaseHelper(true /* forMigration */);
         try {
-            return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper,
-                   oldHelper.getWritableDatabase());
+            // 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);
+            return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, srcDeviceState,
+                    destDeviceState, mOpenHelper, oldHelper.getWritableDatabase());
         } catch (Exception e) {
             FileLog.e(TAG, "Failed to migrate grid", e);
             return false;
@@ -313,6 +329,30 @@
     }
 
     /**
+     * In case of migration failure, report metrics for the count of each itemType in the DB.
+     * @param restoreEventLogger logger used to report Launcher restore metrics
+     */
+    private void sendMetricsForFailedMigration(LauncherRestoreEventLogger restoreEventLogger,
+            SQLiteDatabase db) {
+        try (Cursor cursor = db.rawQuery(
+                "SELECT itemType, COUNT(*) AS count FROM favorites GROUP BY itemType",
+                null
+        )) {
+            if (cursor.moveToFirst()) {
+                do {
+                    restoreEventLogger.logFavoritesItemsRestoreFailed(
+                            cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
+                            cursor.getInt(cursor.getColumnIndexOrThrow("count")),
+                            RestoreError.GRID_MIGRATION_FAILURE
+                    );
+                } while (cursor.moveToNext());
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "sendMetricsForFailedDb: Error reading from database", e);
+        }
+    }
+
+    /**
      * Returns the underlying model database
      */
     public SQLiteDatabase getDb() {
@@ -355,6 +395,68 @@
         }
     }
 
+    /**
+     * Deletes any app pair that doesn't contain 2 member apps from the DB.
+     * @return Ids of deleted app pairs.
+     */
+    @WorkerThread
+    public IntArray deleteBadAppPairs() {
+        createDbIfNotExists();
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+            // Select all entries with ITEM_TYPE = ITEM_TYPE_APP_PAIR whose id does not appear
+            // exactly twice in the CONTAINER column.
+            String selection =
+                    ITEM_TYPE + " = " + ITEM_TYPE_APP_PAIR
+                            + " AND " + _ID +  " NOT IN"
+                            + " (SELECT " + CONTAINER + " FROM " + TABLE_NAME
+                            + " GROUP BY " + CONTAINER + " HAVING COUNT(*) = 2)";
+
+            IntArray appPairIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+                    _ID, selection, null, null);
+            if (!appPairIds.isEmpty()) {
+                db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+                        _ID, appPairIds), null);
+            }
+            t.commit();
+            return appPairIds;
+        } catch (SQLException ex) {
+            Log.e(TAG, ex.getMessage(), ex);
+            return new IntArray();
+        }
+    }
+
+    /**
+     * Deletes any app with a container id that doesn't exist.
+     * @return Ids of deleted apps.
+     */
+    @WorkerThread
+    public IntArray deleteUnparentedApps() {
+        createDbIfNotExists();
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+            // Select all entries whose container id does not appear in the database.
+            String selection =
+                    CONTAINER + " >= 0"
+                            + " AND " + CONTAINER + " NOT IN"
+                            + " (SELECT " + _ID + " FROM " + TABLE_NAME + ")";
+
+            IntArray appIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+                    _ID, selection, null, null);
+            if (!appIds.isEmpty()) {
+                db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+                        _ID, appIds), null);
+            }
+            t.commit();
+            return appIds;
+        } catch (SQLException ex) {
+            Log.e(TAG, ex.getMessage(), ex);
+            return new IntArray();
+        }
+    }
+
     private static void addModifiedTime(ContentValues values) {
         values.put(LauncherSettings.Favorites.MODIFIED, System.currentTimeMillis());
     }
@@ -426,7 +528,7 @@
             LauncherWidgetHolder widgetHolder) {
         ContentResolver cr = mContext.getContentResolver();
         String blobHandlerDigest = Settings.Secure.getString(cr, LAYOUT_DIGEST_KEY);
-        if (Utilities.ATLEAST_R && !TextUtils.isEmpty(blobHandlerDigest)) {
+        if (!TextUtils.isEmpty(blobHandlerDigest)) {
             BlobStoreManager blobManager = mContext.getSystemService(BlobStoreManager.class);
             try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
                     blobManager.openBlob(BlobHandle.createWithSha256(
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 7e7bfb3..8360b14 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -45,28 +45,29 @@
             boolean isPrimaryInstance) {
         ModelDelegate delegate = Overrides.getObject(
                 ModelDelegate.class, context, R.string.model_delegate_class);
-        delegate.init(context, app, appsList, dataModel, isPrimaryInstance);
+        delegate.init(app, appsList, dataModel, isPrimaryInstance);
         return delegate;
     }
 
-    protected Context mContext;
+    protected final Context mContext;
     protected LauncherAppState mApp;
     protected AllAppsList mAppsList;
     protected BgDataModel mDataModel;
     protected boolean mIsPrimaryInstance;
 
-    public ModelDelegate() { }
+    public ModelDelegate(Context context) {
+        mContext = context;
+    }
 
     /**
      * Initializes the object with the given params.
      */
-    private void init(Context context, LauncherAppState app, AllAppsList appsList,
+    private void init(LauncherAppState app, AllAppsList appsList,
             BgDataModel dataModel, boolean isPrimaryInstance) {
         this.mApp = app;
         this.mAppsList = appsList;
         this.mDataModel = dataModel;
         this.mIsPrimaryInstance = isPrimaryInstance;
-        this.mContext = context;
     }
 
     /** Called periodically to validate and update any data */
diff --git a/src/com/android/launcher3/model/ModelLauncherCallbacks.kt b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
new file mode 100644
index 0000000..b12b2bc
--- /dev/null
+++ b/src/com/android/launcher3/model/ModelLauncherCallbacks.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.content.pm.LauncherApps
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.text.TextUtils
+import com.android.launcher3.LauncherModel.ModelUpdateTask
+import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.PackageUpdatedTask.OP_ADD
+import com.android.launcher3.model.PackageUpdatedTask.OP_REMOVE
+import com.android.launcher3.model.PackageUpdatedTask.OP_SUSPEND
+import com.android.launcher3.model.PackageUpdatedTask.OP_UNAVAILABLE
+import com.android.launcher3.model.PackageUpdatedTask.OP_UNSUSPEND
+import com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE
+import java.util.function.Consumer
+
+/**
+ * Implementation of {@link LauncherApps#Callbacks} which converts various events to corresponding
+ * model tasks
+ */
+class ModelLauncherCallbacks(private var taskExecutor: Consumer<ModelUpdateTask>) :
+    LauncherApps.Callback() {
+
+    override fun onPackageAdded(packageName: String, user: UserHandle) {
+        taskExecutor.accept(PackageUpdatedTask(OP_ADD, user, packageName))
+    }
+
+    override fun onPackageChanged(packageName: String, user: UserHandle) {
+        taskExecutor.accept(PackageUpdatedTask(OP_UPDATE, user, packageName))
+    }
+
+    override fun onPackageLoadingProgressChanged(
+        packageName: String,
+        user: UserHandle,
+        progress: Float
+    ) {
+        taskExecutor.accept(PackageIncrementalDownloadUpdatedTask(packageName, user, progress))
+    }
+
+    override fun onPackageRemoved(packageName: String, user: UserHandle) {
+        FileLog.d(TAG, "package removed received $packageName")
+        taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, packageName))
+    }
+
+    override fun onPackagesAvailable(
+        vararg packageNames: String,
+        user: UserHandle,
+        replacing: Boolean
+    ) {
+        taskExecutor.accept(PackageUpdatedTask(OP_UPDATE, user, *packageNames))
+    }
+
+    override fun onPackagesSuspended(vararg packageNames: String, user: UserHandle) {
+        taskExecutor.accept(PackageUpdatedTask(OP_SUSPEND, user, *packageNames))
+    }
+
+    override fun onPackagesUnavailable(
+        packageNames: Array<String>,
+        user: UserHandle,
+        replacing: Boolean
+    ) {
+        if (!replacing) {
+            taskExecutor.accept(PackageUpdatedTask(OP_UNAVAILABLE, user, *packageNames))
+        }
+    }
+
+    override fun onPackagesUnsuspended(vararg packageNames: String, user: UserHandle) {
+        taskExecutor.accept(PackageUpdatedTask(OP_UNSUSPEND, user, *packageNames))
+    }
+
+    override fun onShortcutsChanged(
+        packageName: String,
+        shortcuts: MutableList<ShortcutInfo>,
+        user: UserHandle
+    ) {
+        taskExecutor.accept(ShortcutsChangedTask(packageName, shortcuts, user, true))
+    }
+
+    fun onPackagesRemoved(user: UserHandle, packages: List<String>) {
+        FileLog.d(TAG, "package removed received " + TextUtils.join(",", packages))
+        taskExecutor.accept(PackageUpdatedTask(OP_REMOVE, user, *packages.toTypedArray()))
+    }
+
+    companion object {
+        private const val TAG = "LauncherAppsCallbackImpl"
+    }
+}
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index bc51c9b..9e72e28 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -20,7 +20,6 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -37,9 +36,9 @@
      */
     public static <T extends ItemInfo> void filterCurrentWorkspaceItems(
             final IntSet currentScreenIds,
-            ArrayList<T> allWorkspaceItems,
-            ArrayList<T> currentScreenItems,
-            ArrayList<T> otherScreenItems) {
+            List<? extends T> allWorkspaceItems,
+            List<T> currentScreenItems,
+            List<T> otherScreenItems) {
         // Purge any null ItemInfos
         allWorkspaceItems.removeIf(Objects::isNull);
         // Order the set of items by their containers first, this allows use to walk through the
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 55093a3..b477cb1 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -37,7 +37,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -275,7 +275,7 @@
     public void deleteItemsFromDatabase(@NonNull final Predicate<ItemInfo> matcher,
             @Nullable final String reason) {
         deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
-                        .filter(matcher).collect(Collectors.toList()), reason);
+                .filter(matcher).collect(Collectors.toList()), reason);
     }
 
     /**
@@ -302,15 +302,15 @@
     /**
      * Remove the specified folder and all its contents from the database.
      */
-    public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
+    public void deleteCollectionAndContentsFromDatabase(final CollectionInfo info) {
         ModelVerifier verifier = new ModelVerifier();
         notifyDelete(Collections.singleton(info));
 
         enqueueDeleteRunnable(newModelTask(() -> {
             mModel.getModelDbController().delete(Favorites.TABLE_NAME,
                     Favorites.CONTAINER + "=" + info.id, null);
-            mBgDataModel.removeItem(mContext, info.contents);
-            info.contents.clear();
+            mBgDataModel.removeItem(mContext, info.getContents());
+            info.getContents().clear();
 
             mModel.getModelDbController().delete(Favorites.TABLE_NAME,
                     Favorites._ID + "=" + info.id, null);
@@ -458,12 +458,12 @@
 
                 if (item.container != Favorites.CONTAINER_DESKTOP &&
                         item.container != Favorites.CONTAINER_HOTSEAT) {
-                    // Item is in a folder, make sure this folder exists
-                    if (!mBgDataModel.folders.containsKey(item.container)) {
+                    // Item is in a collection, make sure this collection exists
+                    if (!mBgDataModel.collections.containsKey(item.container)) {
                         // An items container is being set to a that of an item which is not in
                         // the list of Folders.
                         String msg = "item: " + item + " container being set to: " +
-                                item.container + ", not in the list of folders";
+                                item.container + ", not in the list of collections";
                         Log.e(TAG, msg);
                     }
                 }
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 76a87ed..2457a42 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -52,7 +52,8 @@
                 ApplicationInfo ai = app.getContext()
                         .getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
                 if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) {
-                    app.getModel().onPackageAdded(ai.packageName, mInstallInfo.user);
+                    app.getModel().newModelCallbacks()
+                            .onPackageAdded(ai.packageName, mInstallInfo.user);
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 // Ignore
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 4f2d398..6432d33 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_WORK_PROFILE_QUIET_MODE_ENABLED;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
 import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_RESTORED_ICON;
 
@@ -37,6 +38,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.FileLog;
@@ -46,6 +48,7 @@
 import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
@@ -67,6 +70,7 @@
  * Handles updates due to changes in package manager (app installed/updated/removed)
  * or when a user availability changes.
  */
+@SuppressWarnings("NewApi")
 public class PackageUpdatedTask extends BaseModelUpdateTask {
 
     // TODO(b/290090023): Set to false after root causing is done.
@@ -237,8 +241,9 @@
                                 isTargetValid = context.getSystemService(LauncherApps.class)
                                         .isActivityEnabled(cn, mUser);
                             }
-                            if (!isTargetValid && si.hasStatusFlag(
-                                    FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)) {
+                            if (!isTargetValid && (si.hasStatusFlag(
+                                    FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)
+                                    || si.isArchived())) {
                                 if (updateWorkspaceItemIntent(context, si, packageName)) {
                                     infoUpdated = true;
                                 } else if (si.hasPromiseIconUi()) {
@@ -269,7 +274,21 @@
                                             : PackageManagerHelper.getLoadingProgress(
                                                     activities.get(0)),
                                     PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+                            // In case an app is archived, we need to make sure that archived state
+                            // in WorkspaceItemInfo is refreshed.
+                            if (Flags.enableSupportForArchiving() && !activities.isEmpty()) {
+                                boolean newArchivalState = activities.get(
+                                        0).getActivityInfo().isArchived;
+                                if (newArchivalState != si.isArchived()) {
+                                    si.runtimeStatusFlags ^= FLAG_ARCHIVED;
+                                    infoUpdated = true;
+                                }
+                            }
                             if (si.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+                                if (activities != null && !activities.isEmpty()) {
+                                    si.setNonResizeable(ApiWrapper.INSTANCE.get(context)
+                                            .isNonResizeableActivity(activities.get(0)));
+                                }
                                 iconCache.getTitleAndIcon(si, si.usingLowResIcon());
                                 infoUpdated = true;
                             }
@@ -340,9 +359,10 @@
         }
 
         if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
-            Predicate<ItemInfo> removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
-                    .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
-                    .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
+            Predicate<ItemInfo> removeMatch =
+                    ItemInfoMatcher.ofPackages(removedPackages, mUser)
+                            .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
+                            .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
             deleteAndBindComponentsRemoved(removeMatch,
                     "removed because the corresponding package or component is removed. "
                             + "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 3798575..5293316 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -52,7 +52,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
-        final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
+        final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
         for (PackageUserKey puk : mPackages) {
             UserHandle user = puk.mUser;
 
@@ -67,11 +67,10 @@
                 }
             }
             if (!packagesRemoved.isEmpty()) {
-                mModel.onPackagesRemoved(user,
-                        packagesRemoved.toArray(new String[packagesRemoved.size()]));
+                mModel.newModelCallbacks().onPackagesRemoved(user, packagesRemoved);
             }
             if (!packagesUnavailable.isEmpty()) {
-                mModel.onPackagesUnavailable(
+                mModel.newModelCallbacks().onPackagesUnavailable(
                         packagesUnavailable.toArray(new String[packagesUnavailable.size()]),
                         user, false);
             }
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index a6a04a7..1cb5215 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -78,10 +78,12 @@
 
         if (!matchingWorkspaceItems.isEmpty()) {
             if (mShortcuts.isEmpty()) {
+                PackageManagerHelper packageManagerHelper = PackageManagerHelper.INSTANCE.get(
+                        app.getContext());
                 // Verify that the app is indeed installed.
-                if (!new PackageManagerHelper(app.getContext())
-                        .isAppInstalled(mPackageName, mUser)) {
-                    // App is not installed, ignoring package events
+                if (!packageManagerHelper.isAppInstalled(mPackageName, mUser)
+                        && !packageManagerHelper.isAppArchivedForUser(mPackageName, mUser)) {
+                    // App is not installed or archived, ignoring package events
                     return;
                 }
             }
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index c99b889..3f88717 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -1,5 +1,9 @@
 package com.android.launcher3.model;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
+
 import static com.android.launcher3.Utilities.ATLEAST_S;
 
 import android.annotation.SuppressLint;
@@ -7,13 +11,20 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
 
+import androidx.core.os.BuildCompat;
+
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.pm.ShortcutConfigActivityInfo;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetManagerHelper;
 
 /**
  * An wrapper over various items displayed in a widget picker,
@@ -25,12 +36,15 @@
     public final LauncherAppWidgetProviderInfo widgetInfo;
     public final ShortcutConfigActivityInfo activityInfo;
 
+    public BitmapInfo bitmap = BitmapInfo.LOW_RES_INFO;
     public final String label;
     public final CharSequence description;
     public final int spanX, spanY;
+    public final SparseArray<RemoteViews> generatedPreviews;
 
     public WidgetItem(LauncherAppWidgetProviderInfo info,
-            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+            InvariantDeviceProfile idp, IconCache iconCache, Context context,
+            WidgetManagerHelper helper) {
         super(info.provider, info.getProfile());
 
         label = iconCache.getTitleNoCache(info);
@@ -40,6 +54,27 @@
 
         spanX = Math.min(info.spanX, idp.numColumns);
         spanY = Math.min(info.spanY, idp.numRows);
+
+        if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews()) {
+            generatedPreviews = new SparseArray<>(3);
+            for (int widgetCategory : new int[] {
+                    WIDGET_CATEGORY_HOME_SCREEN,
+                    WIDGET_CATEGORY_KEYGUARD,
+                    WIDGET_CATEGORY_SEARCHBOX,
+            }) {
+                if ((widgetCategory & widgetInfo.generatedPreviewCategories) != 0) {
+                    generatedPreviews.put(widgetCategory,
+                            helper.loadGeneratedPreview(widgetInfo, widgetCategory));
+                }
+            }
+        } else {
+            generatedPreviews = null;
+        }
+    }
+
+    public WidgetItem(LauncherAppWidgetProviderInfo info,
+            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+        this(info, idp, iconCache, context, new WidgetManagerHelper(context));
     }
 
     public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
@@ -50,6 +85,7 @@
         widgetInfo = null;
         activityInfo = info;
         spanX = spanY = 1;
+        generatedPreviews = null;
     }
 
     /**
@@ -78,4 +114,16 @@
     public boolean isShortcut() {
         return activityInfo != null;
     }
+
+    /**
+     * Returns whether this {@link WidgetItem} has a generated preview for the given widget
+     * category.
+     */
+    public boolean hasGeneratedPreview(int widgetCategory) {
+        if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
+            return false;
+        }
+        return generatedPreviews.contains(widgetCategory)
+                && generatedPreviews.get(widgetCategory) != null;
+    }
 }
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
similarity index 79%
rename from src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
rename to src/com/android/launcher3/model/WidgetsModel.java
index 2f16065..5e0edb3 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -3,6 +3,7 @@
 
 import static android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_HIDE_FROM_PICKER;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.pm.ShortcutConfigActivityInfo.queryList;
 import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
 
@@ -44,6 +45,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -59,10 +61,6 @@
  */
 public class WidgetsModel {
 
-    // True is the widget support is disabled.
-    public static final boolean GO_DISABLE_WIDGETS = false;
-    public static final boolean GO_DISABLE_NOTIFICATION_DOTS = false;
-
     private static final String TAG = "WidgetsModel";
     private static final boolean DEBUG = false;
 
@@ -70,6 +68,37 @@
     private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
 
     /**
+     * Returns a list of {@link WidgetsListBaseEntry} filtered using given widget item filter. All
+     * {@link WidgetItem}s in a single row are sorted (based on label and user), but the overall
+     * list of {@link WidgetsListBaseEntry}s is not sorted.
+     *
+     * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
+     */
+    public synchronized ArrayList<WidgetsListBaseEntry> getFilteredWidgetsListForPicker(
+            Context context,
+            Predicate<WidgetItem> widgetItemFilter) {
+        if (!WIDGETS_ENABLED) {
+            return new ArrayList<>();
+        }
+        ArrayList<WidgetsListBaseEntry> result = new ArrayList<>();
+        AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
+
+        for (Map.Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
+            PackageItemInfo pkgItem = entry.getKey();
+            List<WidgetItem> widgetItems = entry.getValue()
+                    .stream()
+                    .filter(widgetItemFilter).toList();
+            if (!widgetItems.isEmpty()) {
+                String sectionName = (pkgItem.title == null) ? "" :
+                        indexer.computeSectionName(pkgItem.title);
+                result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
+                result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
+            }
+        }
+        return result;
+    }
+
+    /**
      * Returns a list of {@link WidgetsListBaseEntry}. All {@link WidgetItem} in a single row
      * are sorted (based on label and user), but the overall list of
      * {@link WidgetsListBaseEntry}s is not sorted.
@@ -77,27 +106,20 @@
      * @see com.android.launcher3.widget.picker.WidgetsListAdapter#setWidgets(List)
      */
     public synchronized ArrayList<WidgetsListBaseEntry> getWidgetsListForPicker(Context context) {
-        ArrayList<WidgetsListBaseEntry> result = new ArrayList<>();
-        AlphabeticIndexCompat indexer = new AlphabeticIndexCompat(context);
-
-        for (Map.Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
-            PackageItemInfo pkgItem = entry.getKey();
-            List<WidgetItem> widgetItems = entry.getValue();
-            String sectionName = (pkgItem.title == null) ? "" :
-                    indexer.computeSectionName(pkgItem.title);
-            result.add(WidgetsListHeaderEntry.create(pkgItem, sectionName, widgetItems));
-            result.add(new WidgetsListContentEntry(pkgItem, sectionName, widgetItems));
-        }
-        return result;
+        // return all items
+        return getFilteredWidgetsListForPicker(context, /*widgetItemFilter=*/ item -> true);
     }
 
     /** Returns a mapping of packages to their widgets without static shortcuts. */
     public synchronized Map<PackageUserKey, List<WidgetItem>> getAllWidgetsWithoutShortcuts() {
+        if (!WIDGETS_ENABLED) {
+            return Collections.emptyMap();
+        }
         Map<PackageUserKey, List<WidgetItem>> packagesToWidgets = new HashMap<>();
         mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) -> {
             List<WidgetItem> widgets = widgetsAndShortcuts.stream()
-                        .filter(item -> item.widgetInfo != null)
-                        .collect(toList());
+                    .filter(item -> item.widgetInfo != null)
+                    .collect(toList());
             if (widgets.size() > 0) {
                 packagesToWidgets.put(
                         new PackageUserKey(packageItemInfo.packageName, packageItemInfo.user),
@@ -113,6 +135,9 @@
      */
     public List<ComponentWithLabelAndIcon> update(
             LauncherAppState app, @Nullable PackageUserKey packageUser) {
+        if (!WIDGETS_ENABLED) {
+            return Collections.emptyList();
+        }
         Preconditions.assertWorkerThread();
 
         Context context = app.getContext();
@@ -129,7 +154,8 @@
                         LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
 
                 widgetsAndShortcuts.add(new WidgetItem(
-                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
+                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext(),
+                        widgetManager));
                 updatedItems.add(launcherWidgetInfo);
             }
 
@@ -188,6 +214,10 @@
 
     public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
             LauncherAppState app) {
+        if (!WIDGETS_ENABLED) {
+            return;
+        }
+        WidgetManagerHelper widgetManager = new WidgetManagerHelper(app.getContext());
         for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
             if (packageNames.contains(entry.getKey().packageName)) {
                 List<WidgetItem> items = entry.getValue();
@@ -201,7 +231,7 @@
                         } else {
                             items.set(i, new WidgetItem(item.widgetInfo,
                                     app.getInvariantDeviceProfile(), app.getIconCache(),
-                                    app.getContext()));
+                                    app.getContext(), widgetManager));
                         }
                     }
                 }
@@ -209,17 +239,45 @@
         }
     }
 
+    private PackageItemInfo createPackageItemInfo(
+            ComponentName providerName,
+            UserHandle user,
+            int category
+    ) {
+        if (category == NO_CATEGORY) {
+            return new PackageItemInfo(providerName.getPackageName(), user);
+        } else {
+            return new PackageItemInfo("" , category, user);
+        }
+    }
+
+    private IntSet getCategories(ComponentName providerName, Context context) {
+        IntSet categories = WidgetSections.getWidgetsToCategory(context).get(providerName);
+        if (categories != null) {
+            return categories;
+        }
+        categories = new IntSet();
+        categories.add(NO_CATEGORY);
+        return categories;
+    }
+
     public WidgetItem getWidgetProviderInfoByProviderName(
-            ComponentName providerName, UserHandle user) {
-        List<WidgetItem> widgetsList = mWidgetsList.get(
-                new PackageItemInfo(providerName.getPackageName(), user));
-        if (widgetsList == null) {
+            ComponentName providerName, UserHandle user, Context context) {
+        if (!WIDGETS_ENABLED) {
             return null;
         }
+        IntSet categories = getCategories(providerName, context);
 
-        for (WidgetItem item : widgetsList) {
-            if (item.componentName.equals(providerName)) {
-                return item;
+        // Checking if we have a provider in any of the categories.
+        for (Integer category: categories) {
+            PackageItemInfo key = createPackageItemInfo(providerName, user, category);
+            List<WidgetItem> widgets = mWidgetsList.get(key);
+            if (widgets != null) {
+                return widgets.stream().filter(
+                                item -> item.componentName.equals(providerName)
+                        )
+                        .findFirst()
+                        .orElse(null);
             }
         }
         return null;
@@ -319,4 +377,4 @@
             return mMap.values();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
new file mode 100644
index 0000000..cea4380
--- /dev/null
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model
+
+import android.annotation.SuppressLint
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.content.pm.ShortcutInfo
+import android.graphics.Point
+import android.text.TextUtils
+import android.util.Log
+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.Utilities
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.ItemInfoWithIcon
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.PackageInstallInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.WidgetInflater
+import com.android.launcher3.widget.util.WidgetSizes
+
+/**
+ * This items is used by LoaderTask to process items that have been loaded from the Launcher's DB.
+ * This data, stored in the Favorites table, needs to be processed in order to be shown on the Home
+ * Page.
+ *
+ * This class processes each of those items: App Shortcuts, Widgets, Folders, etc., one at a time.
+ */
+class WorkspaceItemProcessor(
+    private val c: LoaderCursor,
+    private val memoryLogger: LoaderMemoryLogger?,
+    private val userCache: UserCache,
+    private val userManagerState: UserManagerState,
+    private val launcherApps: LauncherApps,
+    private val pendingPackages: MutableSet<PackageUserKey>,
+    private val shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo>,
+    private val app: LauncherAppState,
+    private val bgDataModel: BgDataModel,
+    private val widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?>,
+    private val installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>,
+    private val isSdCardReady: Boolean,
+    private val widgetInflater: WidgetInflater,
+    private val pmHelper: PackageManagerHelper,
+    private val iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>,
+    private val unlockedUsers: LongSparseArray<Boolean>,
+    private val allDeepShortcuts: MutableList<ShortcutInfo>
+) {
+
+    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
+     * that delegates the actual processing to either processAppShortcut, processFolder, or
+     * processWidget depending on what type of item is being processed.
+     *
+     * All the parameters are expected to be shared between many repeated calls of this method, one
+     * for each workspace item.
+     */
+    fun processItem() {
+        try {
+            if (c.user == null) {
+                // User has been deleted, remove the item.
+                c.markDeleted(
+                    "User has been deleted for item id=${c.id}",
+                    RestoreError.PROFILE_DELETED
+                )
+                return
+            }
+            when (c.itemType) {
+                Favorites.ITEM_TYPE_APPLICATION,
+                Favorites.ITEM_TYPE_DEEP_SHORTCUT -> processAppOrDeepShortcut()
+                Favorites.ITEM_TYPE_FOLDER,
+                Favorites.ITEM_TYPE_APP_PAIR -> processFolderOrAppPair()
+                Favorites.ITEM_TYPE_APPWIDGET,
+                Favorites.ITEM_TYPE_CUSTOM_APPWIDGET -> processWidget()
+            }
+        } catch (e: Exception) {
+            Log.e(TAG, "Desktop items loading interrupted", e)
+        }
+    }
+
+    /**
+     * This method verifies that an app shortcut should be shown on the home screen, updates the
+     * database accordingly, formats the data in such a way that it is ready to be added to the data
+     * model, and then adds it to the launcher’s data model.
+     *
+     * In this method, verification means that an an app shortcut database entry is required to:
+     * Have a Launch Intent. This is how the app component symbolized by the shortcut is launched.
+     * Have a Package Name. Not be in a funky “Restoring, but never actually restored” state. Not
+     * have null or missing ShortcutInfos or ItemInfos in other data models.
+     *
+     * If any of the above are found to be true, the database entry is deleted, and not shown on the
+     * user’s home screen. When an app is verified, it is marked as restored, meaning that the app
+     * is viable to show on the home screen.
+     *
+     * In order to accommodate different types and versions of App Shortcuts, different properties
+     * and flags are set on the ItemInfo objects that are added to the data model. For example,
+     * icons that are not a part of the workspace or hotseat are marked as using low resolution icon
+     * bitmaps. Currently suspended app icons are marked as such. Installing packages are also
+     * marked as such. Lastly, after applying common properties to the ItemInfo, it is added to the
+     * data model to be bound to the launcher’s data model.
+     */
+    @SuppressLint("NewApi")
+    private fun processAppOrDeepShortcut() {
+        var allowMissingTarget = false
+        var intent = c.parseIntent()
+        if (intent == null) {
+            c.markDeleted("Null intent from db for item id=${c.id}", RestoreError.MISSING_INFO)
+            return
+        }
+        var disabledState =
+            if (userManagerState.isUserQuiet(c.serialNumber))
+                WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER
+            else 0
+        val cn = intent.component
+        val targetPkg = cn?.packageName ?: intent.getPackage()
+        if (targetPkg.isNullOrEmpty()) {
+            c.markDeleted("No target package for item id=${c.id}", RestoreError.MISSING_INFO)
+            return
+        }
+        var validTarget = launcherApps.isPackageEnabled(targetPkg, c.user)
+
+        // If it's a deep shortcut, we'll use pinned shortcuts to restore it
+        if (cn != null && validTarget && (c.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT)) {
+            // If the apk is present and the shortcut points to a specific component.
+
+            // If the component is already present
+            if (launcherApps.isActivityEnabled(cn, c.user)) {
+                // no special handling necessary for this item
+                c.markRestored()
+            } else {
+                // Gracefully try to find a fallback activity.
+                FileLog.d(
+                    TAG,
+                    "Activity not enabled for id=${c.id}, component=$cn, user=${c.user}." +
+                        " Will attempt to find fallback Activity for targetPkg=$targetPkg."
+                )
+                intent = pmHelper.getAppLaunchIntent(targetPkg, c.user)
+                if (intent != null) {
+                    c.restoreFlag = 0
+                    c.updater().put(Favorites.INTENT, intent.toUri(0)).commit()
+                } else {
+                    c.markDeleted(
+                        "No Activities found for id=${c.id}, targetPkg=$targetPkg, component=$cn." +
+                            " Unable to create launch Intent.",
+                        RestoreError.MISSING_INFO
+                    )
+                    return
+                }
+            }
+        }
+        if (intent.`package` == null) {
+            intent.`package` = targetPkg
+        }
+        // else if cn == null => can't infer much, leave it
+        // else if !validPkg => could be restored icon or missing sd-card
+        when {
+            !TextUtils.isEmpty(targetPkg) && !validTarget -> {
+                // Points to a valid app (superset of cn != null) but the apk
+                // is not available.
+                when {
+                    c.restoreFlag != 0 -> {
+                        // Package is not yet available but might be
+                        // installed later.
+                        FileLog.d(TAG, "package not yet restored: $targetPkg")
+                        tempPackageKey.update(targetPkg, c.user)
+                        when {
+                            c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED) -> {
+                                // Restore has started once.
+                            }
+                            installingPkgs.containsKey(tempPackageKey) -> {
+                                // App restore has started. Update the flag
+                                c.restoreFlag =
+                                    c.restoreFlag or WorkspaceItemInfo.FLAG_RESTORE_STARTED
+                                FileLog.d(TAG, "restore started for installing app: $targetPkg")
+                                c.updater().put(Favorites.RESTORED, c.restoreFlag).commit()
+                            }
+                            else -> {
+                                c.markDeleted(
+                                    "removing app that is not restored and not installing. package: $targetPkg",
+                                    RestoreError.APP_NOT_INSTALLED
+                                )
+                                return
+                            }
+                        }
+                    }
+                    pmHelper.isAppOnSdcard(targetPkg, c.user) -> {
+                        // Package is present but not available.
+                        disabledState =
+                            disabledState or WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE
+                        // Add the icon on the workspace anyway.
+                        allowMissingTarget = true
+                    }
+                    !isSdCardReady -> {
+                        // SdCard is not ready yet. Package might get available,
+                        // once it is ready.
+                        Log.d(TAG, "Missing package, will check later: $targetPkg")
+                        pendingPackages.add(PackageUserKey(targetPkg, c.user))
+                        // Add the icon on the workspace anyway.
+                        allowMissingTarget = true
+                    }
+                    else -> {
+                        // Do not wait for external media load anymore.
+                        c.markDeleted(
+                            "Invalid package removed: $targetPkg",
+                            RestoreError.APP_NOT_INSTALLED
+                        )
+                        return
+                    }
+                }
+            }
+        }
+        if (c.restoreFlag and WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI != 0) {
+            validTarget = false
+        }
+        if (validTarget) {
+            // The shortcut points to a valid target (either no target
+            // or something which is ready to be used)
+            c.markRestored()
+        }
+        val useLowResIcon = !c.isOnWorkspaceOrHotseat
+        val info: WorkspaceItemInfo?
+        when {
+            c.restoreFlag != 0 -> {
+                // Already verified above that user is same as default user
+                info = c.getRestoredItemInfo(intent)
+            }
+            c.itemType == Favorites.ITEM_TYPE_APPLICATION ->
+                info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon, false)
+            c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT -> {
+                val key = ShortcutKey.fromIntent(intent, c.user)
+                if (unlockedUsers[c.serialNumber]) {
+                    val pinnedShortcut = shortcutKeyToPinnedShortcuts[key]
+                    if (pinnedShortcut == null) {
+                        // The shortcut is no longer valid.
+                        c.markDeleted(
+                            "Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}",
+                            RestoreError.SHORTCUT_NOT_FOUND
+                        )
+                        return
+                    }
+                    info = WorkspaceItemInfo(pinnedShortcut, app.context)
+                    // If the pinned deep shortcut is no longer published,
+                    // use the last saved icon instead of the default.
+                    iconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon)
+                    if (pmHelper.isAppSuspended(pinnedShortcut.getPackage(), info.user)) {
+                        info.runtimeStatusFlags =
+                            info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
+                    }
+                    intent = info.getIntent()
+                    allDeepShortcuts.add(pinnedShortcut)
+                } else {
+                    // Create a shortcut info in disabled mode for now.
+                    info = c.loadSimpleWorkspaceItem()
+                    info.runtimeStatusFlags =
+                        info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER
+                }
+            }
+            else -> { // item type == ITEM_TYPE_SHORTCUT
+                info = c.loadSimpleWorkspaceItem()
+
+                // Shortcuts are only available on the primary profile
+                if (!TextUtils.isEmpty(targetPkg) && pmHelper.isAppSuspended(targetPkg, c.user)) {
+                    disabledState = disabledState or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
+                }
+                info.options = c.options
+
+                // App shortcuts that used to be automatically added to Launcher
+                // didn't always have the correct intent flags set, so do that here
+                if (
+                    intent.action != null &&
+                        intent.categories != null &&
+                        intent.action == Intent.ACTION_MAIN &&
+                        intent.categories.contains(Intent.CATEGORY_LAUNCHER)
+                ) {
+                    intent.addFlags(
+                        Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                    )
+                }
+            }
+        }
+        if (info != null) {
+            if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                // Skip deep shortcuts; their title and icons have already been
+                // loaded above.
+                iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon))
+            }
+            c.applyCommonProperties(info)
+            info.intent = intent
+            info.rank = c.rank
+            info.spanX = 1
+            info.spanY = 1
+            info.runtimeStatusFlags = info.runtimeStatusFlags or disabledState
+            if (isSafeMode && !PackageManagerHelper.isSystemApp(app.context, intent)) {
+                info.runtimeStatusFlags =
+                    info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE
+            }
+            val activityInfo = c.launcherActivityInfo
+            if (activityInfo != null) {
+                AppInfo.updateRuntimeFlagsForActivityTarget(
+                    info,
+                    activityInfo,
+                    userCache.getUserInfo(c.user),
+                    ApiWrapper.INSTANCE[app.context]
+                )
+            }
+            if (
+                (c.restoreFlag != 0 ||
+                    Flags.enableSupportForArchiving() &&
+                        activityInfo != null &&
+                        activityInfo.applicationInfo.isArchived) && !TextUtils.isEmpty(targetPkg)
+            ) {
+                tempPackageKey.update(targetPkg, c.user)
+                val si = installingPkgs[tempPackageKey]
+                if (si == null) {
+                    info.runtimeStatusFlags =
+                        info.runtimeStatusFlags and
+                            ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE.inv()
+                } else if (
+                    activityInfo == null ||
+                        (Flags.enableSupportForArchiving() &&
+                            activityInfo.applicationInfo.isArchived)
+                ) {
+                    // For archived apps, include progress info in case there is
+                    // a pending install session post restart of device.
+                    val installProgress = (si.getProgress() * 100).toInt()
+                    info.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING)
+                }
+            }
+            c.checkAndAddItem(info, bgDataModel, memoryLogger)
+        } else {
+            throw RuntimeException("Unexpected null WorkspaceItemInfo")
+        }
+    }
+
+    /**
+     * Loads CollectionInfo information from the database and formats it. This function runs while
+     * LoaderTask is still active; some of the processing for folder content items is done after all
+     * the items in the workspace have been loaded. The loaded and formatted CollectionInfo is then
+     * stored in the BgDataModel.
+     */
+    private fun processFolderOrAppPair() {
+        var collection = bgDataModel.findOrMakeFolder(c.id)
+        // If we generated a placeholder Folder before this point, it may need to be replaced with
+        // an app pair.
+        if (c.itemType == Favorites.ITEM_TYPE_APP_PAIR && collection is FolderInfo) {
+            if (!FeatureFlags.enableAppPairs()) {
+                // If app pairs are not enabled, stop loading.
+                Log.e(TAG, "app pairs flag is off, did not load app pair")
+                return
+            }
+
+            val folderInfo: FolderInfo = collection
+            val newAppPair = AppPairInfo()
+            // Move the placeholder's contents over to the new app pair.
+            folderInfo.getContents().forEach(newAppPair::add)
+            collection = newAppPair
+            // Remove the placeholder and add the app pair into the data model.
+            bgDataModel.collections.remove(c.id)
+            bgDataModel.collections.put(c.id, collection)
+        }
+
+        c.applyCommonProperties(collection)
+        // Do not trim the folder label, as is was set by the user.
+        collection.title = c.getString(c.mTitleIndex)
+        collection.spanX = 1
+        collection.spanY = 1
+        if (collection is FolderInfo) {
+            collection.options = c.options
+        } else {
+            // An app pair may be inside another folder, so it needs to preserve rank information.
+            collection.rank = c.rank
+        }
+
+        c.markRestored()
+        c.checkAndAddItem(collection, bgDataModel, memoryLogger)
+    }
+
+    /**
+     * This method, similar to processAppShortcut above, verifies that a widget should be shown on
+     * the home screen, updates the database accordingly, formats the data in such a way that it is
+     * ready to be added to the data model, and then adds it to the launcher’s data model.
+     *
+     * It verifies that: Widgets are not disabled due to the Launcher variety being of the `Go`
+     * type. Search Widgets have a package name. The app behind the widget is still installed on the
+     * device. The app behind the widget is not in a funky “Restoring, but never actually restored”
+     * state. The widget has a valid size. The widget is in the workspace or the hotseat. If any of
+     * the above are found to be true, the database entry is deleted, and the widget is not shown on
+     * the user’s home screen. When a widget is verified, it is marked as restored, meaning that the
+     * widget is viable to show on the home screen.
+     *
+     * Common properties are applied to the Widget’s Info object, and other information as well
+     * depending on the type of widget. Custom widgets are treated differently than non-custom
+     * widgets, installing / restoring widgets are treated differently, etc.
+     */
+    private fun processWidget() {
+        val component = ComponentName.unflattenFromString(c.appWidgetProvider)!!
+        val appWidgetInfo = LauncherAppWidgetInfo(c.appWidgetId, component)
+        c.applyCommonProperties(appWidgetInfo)
+        appWidgetInfo.spanX = c.spanX
+        appWidgetInfo.spanY = c.spanY
+        appWidgetInfo.options = c.options
+        appWidgetInfo.user = c.user
+        appWidgetInfo.sourceContainer = c.appWidgetSource
+        appWidgetInfo.restoreStatus = c.restoreFlag
+        if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
+            c.markDeleted(
+                "processWidget: Widget has invalid size: ${appWidgetInfo.spanX}x${appWidgetInfo.spanY}" +
+                    ", id=${c.id}," +
+                    ", appWidgetId=${c.appWidgetId}," +
+                    ", component=${component}",
+                RestoreError.INVALID_LOCATION
+            )
+            return
+        }
+        if (!c.isOnWorkspaceOrHotseat) {
+            c.markDeleted(
+                "processWidget: invalid Widget container != CONTAINER_DESKTOP nor CONTAINER_HOTSEAT." +
+                    " id=${c.id}," +
+                    ", appWidgetId=${c.appWidgetId}," +
+                    ", component=${component}," +
+                    ", container=${c.container}",
+                RestoreError.INVALID_LOCATION
+            )
+            return
+        }
+        if (appWidgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+            appWidgetInfo.bindOptions = c.parseIntent()
+        }
+        val inflationResult = widgetInflater.inflateAppWidget(appWidgetInfo)
+        var shouldUpdate = inflationResult.isUpdate
+        val lapi = inflationResult.widgetInfo
+        FileLog.d(
+            TAG,
+            "processWidget: id=${c.id}" +
+                ", appWidgetId=${c.appWidgetId}" +
+                ", inflationResult=$inflationResult"
+        )
+        when (inflationResult.type) {
+            WidgetInflater.TYPE_DELETE -> {
+                c.markDeleted(inflationResult.reason, inflationResult.restoreErrorType)
+                return
+            }
+            WidgetInflater.TYPE_PENDING -> {
+                tempPackageKey.update(component.packageName, c.user)
+                val si = installingPkgs[tempPackageKey]
+
+                if (
+                    !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) &&
+                        !isSafeMode &&
+                        (si == null) &&
+                        (lapi == null) &&
+                        !(Flags.enableSupportForArchiving() &&
+                            pmHelper.isAppArchived(component.packageName))
+                ) {
+                    // Restore never started
+                    c.markDeleted(
+                        "processWidget: Unrestored Pending widget removed:" +
+                            " id=${c.id}" +
+                            ", appWidgetId=${c.appWidgetId}" +
+                            ", component=${component}" +
+                            ", restoreFlag:=${c.restoreFlag}",
+                        RestoreError.APP_NOT_INSTALLED
+                    )
+                    return
+                } else if (
+                    !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) && si != null
+                ) {
+                    shouldUpdate = true
+                    appWidgetInfo.restoreStatus =
+                        appWidgetInfo.restoreStatus or LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+                }
+                appWidgetInfo.installProgress =
+                    if (si == null) 0 else (si.getProgress() * 100).toInt()
+                appWidgetInfo.pendingItemInfo =
+                    WidgetsModel.newPendingItemInfo(
+                        app.context,
+                        appWidgetInfo.providerName,
+                        appWidgetInfo.user
+                    )
+                iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
+            }
+            WidgetInflater.TYPE_REAL ->
+                WidgetSizes.updateWidgetSizeRangesAsync(
+                    appWidgetInfo.appWidgetId,
+                    lapi,
+                    app.context,
+                    appWidgetInfo.spanX,
+                    appWidgetInfo.spanY
+                )
+        }
+
+        if (shouldUpdate) {
+            c.updater()
+                .put(Favorites.APPWIDGET_PROVIDER, component.flattenToString())
+                .put(Favorites.APPWIDGET_ID, appWidgetInfo.appWidgetId)
+                .put(Favorites.RESTORED, appWidgetInfo.restoreStatus)
+                .commit()
+        }
+        if (lapi != null) {
+            widgetProvidersMap[ComponentKey(lapi.provider, lapi.user)] = inflationResult.widgetInfo
+            if (appWidgetInfo.spanX < lapi.minSpanX || appWidgetInfo.spanY < lapi.minSpanY) {
+                FileLog.d(
+                    TAG,
+                    " processWidget: Widget ${lapi.component} minSizes not met: span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY} minSpan=${lapi.minSpanX}x${lapi.minSpanY}," +
+                        " id: ${c.id}," +
+                        " appWidgetId: ${c.appWidgetId}," +
+                        " component=${component}"
+                )
+                logWidgetInfo(app.invariantDeviceProfile, lapi)
+            }
+        }
+        c.checkAndAddItem(appWidgetInfo, bgDataModel)
+    }
+
+    companion object {
+        private const val TAG = "WorkspaceItemProcessor"
+
+        private fun logWidgetInfo(
+            idp: InvariantDeviceProfile,
+            widgetProviderInfo: LauncherAppWidgetProviderInfo
+        ) {
+            val cellSize = Point()
+            for (deviceProfile in idp.supportedProfiles) {
+                deviceProfile.getCellSize(cellSize)
+                FileLog.d(
+                    TAG,
+                    "DeviceProfile available width: ${deviceProfile.availableWidthPx}," +
+                        " available height: ${deviceProfile.availableHeightPx}," +
+                        " cellLayoutBorderSpacePx Horizontal: ${deviceProfile.cellLayoutBorderSpacePx.x}," +
+                        " cellLayoutBorderSpacePx Vertical: ${deviceProfile.cellLayoutBorderSpacePx.y}," +
+                        " cellSize: $cellSize"
+                )
+            }
+            val widgetDimension = StringBuilder()
+            widgetDimension
+                .append("Widget dimensions:\n")
+                .append("minResizeWidth: ")
+                .append(widgetProviderInfo.minResizeWidth)
+                .append("\n")
+                .append("minResizeHeight: ")
+                .append(widgetProviderInfo.minResizeHeight)
+                .append("\n")
+                .append("defaultWidth: ")
+                .append(widgetProviderInfo.minWidth)
+                .append("\n")
+                .append("defaultHeight: ")
+                .append(widgetProviderInfo.minHeight)
+                .append("\n")
+            if (Utilities.ATLEAST_S) {
+                widgetDimension
+                    .append("targetCellWidth: ")
+                    .append(widgetProviderInfo.targetCellWidth)
+                    .append("\n")
+                    .append("targetCellHeight: ")
+                    .append(widgetProviderInfo.targetCellHeight)
+                    .append("\n")
+                    .append("maxResizeWidth: ")
+                    .append(widgetProviderInfo.maxResizeWidth)
+                    .append("\n")
+                    .append("maxResizeHeight: ")
+                    .append(widgetProviderInfo.maxResizeHeight)
+                    .append("\n")
+            }
+            FileLog.d(TAG, widgetDimension.toString())
+        }
+    }
+}
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 6c2f589..18aa6e7 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -30,16 +30,21 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.UserIconInfo;
 
 import java.util.Comparator;
 
 /**
  * Represents an app in AllAppsView.
  */
+@SuppressWarnings("NewApi")
 public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
 
     public static final AppInfo[] EMPTY_ARRAY = new AppInfo[0];
@@ -48,12 +53,16 @@
         return uc != 0 ? uc : a.componentName.compareTo(b.componentName);
     };
 
+    public static final Comparator<AppInfo> PACKAGE_KEY_COMPARATOR = Comparator.comparingInt(
+            (AppInfo a) -> a.user.hashCode()).thenComparing(ItemInfo::getTargetPackage);
+
     /**
      * The intent used to start the application.
      */
     public Intent intent;
 
-    @NonNull
+    // componentName for the Private Space Install App button can be null
+    @Nullable
     public ComponentName componentName;
 
     // Section name used for indexing.
@@ -80,20 +89,23 @@
      * Must not hold the Context.
      */
     public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
-        this(info, user, context.getSystemService(UserManager.class).isQuietModeEnabled(user));
+        this(info, UserCache.INSTANCE.get(context).getUserInfo(user),
+                ApiWrapper.INSTANCE.get(context),
+                context.getSystemService(UserManager.class).isQuietModeEnabled(user));
     }
 
-    public AppInfo(LauncherActivityInfo info, UserHandle user, boolean quietModeEnabled) {
+    public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo,
+            ApiWrapper apiWrapper, boolean quietModeEnabled) {
         this.componentName = info.getComponentName();
         this.container = CONTAINER_ALL_APPS;
-        this.user = user;
+        this.user = userIconInfo.user;
         intent = makeLaunchIntent(info);
 
         if (quietModeEnabled) {
             runtimeStatusFlags |= FLAG_DISABLED_QUIET_USER;
         }
         uid = info.getApplicationInfo().uid;
-        updateRuntimeFlagsForActivityTarget(this, info);
+        updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper);
     }
 
     public AppInfo(AppInfo info) {
@@ -166,19 +178,46 @@
         return componentName;
     }
 
-    public static void updateRuntimeFlagsForActivityTarget(
-            ItemInfoWithIcon info, LauncherActivityInfo lai) {
+    /**
+     * Updates the runtime status flags for the given info based on the state of the specified
+     * activity.
+     */
+    public static boolean updateRuntimeFlagsForActivityTarget(
+            ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo,
+            ApiWrapper apiWrapper) {
+        final int oldProgressLevel = info.getProgressLevel();
+        final int oldRuntimeStatusFlags = info.runtimeStatusFlags;
         ApplicationInfo appInfo = lai.getApplicationInfo();
         if (PackageManagerHelper.isAppSuspended(appInfo)) {
             info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
+        } else {
+            info.runtimeStatusFlags &= ~FLAG_DISABLED_SUSPENDED;
+        }
+        if (Flags.enableSupportForArchiving()) {
+            if (lai.getActivityInfo().isArchived) {
+                info.runtimeStatusFlags |= FLAG_ARCHIVED;
+            } else {
+                info.runtimeStatusFlags &= ~FLAG_ARCHIVED;
+            }
         }
         info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
                 ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
 
+        if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+            if (userIconInfo.isPrivate()) {
+                info.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+            } else {
+                info.runtimeStatusFlags &= ~FLAG_NOT_PINNABLE;
+            }
+        }
+
         // Sets the progress level, installation and incremental download flags.
         info.setProgressLevel(
                 PackageManagerHelper.getLoadingProgress(lai),
                 PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+        info.setNonResizeable(apiWrapper.isNonResizeableActivity(lai));
+        return (oldProgressLevel != info.getProgressLevel())
+                || (oldRuntimeStatusFlags != info.runtimeStatusFlags);
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
new file mode 100644
index 0000000..2eb6154
--- /dev/null
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import android.content.Context
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.R
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.views.ActivityContext
+
+/** A type of app collection that launches multiple apps into split screen. */
+class AppPairInfo() : CollectionInfo() {
+    private var contents: ArrayList<WorkspaceItemInfo> = ArrayList()
+
+    init {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
+    }
+
+    /** Convenience constructor, calls primary constructor and init block */
+    constructor(app1: WorkspaceItemInfo, app2: WorkspaceItemInfo) : this() {
+        add(app1)
+        add(app2)
+    }
+
+    /** Creates a new AppPairInfo that is a copy of the provided one. */
+    constructor(appPairInfo: AppPairInfo) : this() {
+        contents = appPairInfo.contents.clone() as ArrayList<WorkspaceItemInfo>
+        copyFrom(appPairInfo)
+    }
+
+    /** Adds an element to the contents ArrayList. */
+    override fun add(item: ItemInfo) {
+        if (item !is WorkspaceItemInfo) {
+            throw RuntimeException("tried to add an illegal type into an app pair")
+        }
+
+        contents.add(item)
+    }
+
+    /** Returns the app pair's member apps as an ArrayList of [ItemInfo]. */
+    override fun getContents(): ArrayList<ItemInfo> =
+        ArrayList(contents.stream().map { it as ItemInfo }.toList())
+
+    /** Returns the app pair's member apps as an ArrayList of [WorkspaceItemInfo]. */
+    override fun getAppContents(): ArrayList<WorkspaceItemInfo> = contents
+
+    /** Returns the first app in the pair. */
+    fun getFirstApp() = contents[0]
+
+    /** Returns the second app in the pair. */
+    fun getSecondApp() = contents[1]
+
+    /** Returns if either of the app pair members is currently disabled. */
+    override fun isDisabled() = anyMatch { it.isDisabled }
+
+    /** Checks if member apps are launchable at the current screen size. */
+    fun isLaunchable(context: Context): Pair<Boolean, Boolean> {
+        val isTablet =
+            (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet
+        return Pair(
+            isTablet || !getFirstApp().isNonResizeable(),
+            isTablet || !getSecondApp().isNonResizeable()
+        )
+    }
+
+    /** Fetches high-res icons for member apps if needed. */
+    fun fetchHiResIconsIfNeeded(iconCache: IconCache) {
+        getAppContents().stream().filter(ItemInfoWithIcon::usingLowResIcon).forEach { member ->
+            iconCache.getTitleAndIcon(member, false)
+        }
+    }
+
+    /**
+     * App pairs will report itself as "disabled" (for accessibility) if either of the following is
+     * true:
+     * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused
+     *    or can't be launched for some other reason).
+     * 2) One of the member apps can't be launched due to screen size requirements.
+     */
+    fun shouldReportDisabled(context: Context): Boolean {
+        return isDisabled || !isLaunchable(context).first || !isLaunchable(context).second
+    }
+
+    /** Generates a default title for the app pair and sets it. */
+    fun generateTitle(context: Context): CharSequence? {
+        val app1: CharSequence? = getFirstApp().title
+        val app2: CharSequence? = getSecondApp().title
+        title = context.getString(R.string.app_pair_default_title, app1, app2)
+        return title
+    }
+
+    /** Generates an ItemInfo for logging. */
+    override fun buildProto(cInfo: CollectionInfo?): LauncherAtom.ItemInfo {
+        val appPairIcon = LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size)
+        appPairIcon.setLabelInfo(title.toString())
+        return getDefaultItemInfoBuilder()
+            .setFolderIcon(appPairIcon)
+            .setRank(rank)
+            .setContainerInfo(getContainerInfo())
+            .build()
+    }
+}
diff --git a/src/com/android/launcher3/model/data/CollectionInfo.kt b/src/com/android/launcher3/model/data/CollectionInfo.kt
new file mode 100644
index 0000000..4f5e12f
--- /dev/null
+++ b/src/com/android/launcher3/model/data/CollectionInfo.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.util.ContentWriter
+import java.util.function.Predicate
+
+abstract class CollectionInfo : ItemInfo() {
+    /** Adds an ItemInfo to the collection. Throws if given an illegal type. */
+    abstract fun add(item: ItemInfo)
+
+    /** Returns the collection's contents as an ArrayList of [ItemInfo]. */
+    abstract fun getContents(): ArrayList<ItemInfo>
+
+    /**
+     * Returns the collection's contents as an ArrayList of [WorkspaceItemInfo]. Does not include
+     * other collection [ItemInfo]s that are inside this collection; rather, it should collect
+     * *their* contents and adds them to the ArrayList.
+     */
+    abstract fun getAppContents(): ArrayList<WorkspaceItemInfo>
+
+    /** Convenience function. Checks contents to see if any match a given predicate. */
+    fun anyMatch(matcher: Predicate<ItemInfo>) = getContents().stream().anyMatch(matcher)
+
+    override fun onAddToDatabase(writer: ContentWriter) {
+        super.onAddToDatabase(writer)
+        writer.put(LauncherSettings.Favorites.TITLE, title)
+    }
+
+    /** Returns the collection wrapped as {@link LauncherAtom.ItemInfo} for logging. */
+    override fun buildProto(): LauncherAtom.ItemInfo {
+        return buildProto(null)
+    }
+}
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 5b541d0..18d2b85 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -24,13 +24,12 @@
 import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
 import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
 
-import android.os.Process;
-
 import androidx.annotation.NonNull;
 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;
@@ -49,7 +48,7 @@
 /**
  * Represents a folder containing shortcuts or apps.
  */
-public class FolderInfo extends ItemInfo {
+public class FolderInfo extends CollectionInfo {
 
     public static final int NO_FLAGS = 0x00000000;
 
@@ -103,24 +102,18 @@
     /**
      * The apps and shortcuts
      */
-    public ArrayList<WorkspaceItemInfo> contents = new ArrayList<>();
+    private final ArrayList<ItemInfo> contents = new ArrayList<>();
 
     private ArrayList<FolderListener> mListeners = new ArrayList<>();
 
     public FolderInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-        user = Process.myUserHandle();
     }
 
-    /**
-     * Create an app pair, a type of app collection that launches multiple apps into split screen
-     */
-    public static FolderInfo createAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
-        FolderInfo newAppPair = new FolderInfo();
-        newAppPair.itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
-        newAppPair.add(app1, /* animate */ false);
-        newAppPair.add(app2, /* animate */ false);
-        return newAppPair;
+    /** Adds a app or shortcut to the contents ArrayList without animation. */
+    @Override
+    public void add(@NonNull ItemInfo item) {
+        add(item, false /* animate */);
     }
 
     /**
@@ -128,16 +121,20 @@
      *
      * @param item
      */
-    public void add(WorkspaceItemInfo item, boolean animate) {
-        add(item, contents.size(), animate);
+    public void add(ItemInfo item, boolean animate) {
+        add(item, getContents().size(), animate);
     }
 
     /**
      * Add an app or shortcut for a specified rank.
      */
-    public void add(WorkspaceItemInfo item, int rank, boolean animate) {
-        rank = Utilities.boundToRange(rank, 0, contents.size());
-        contents.add(rank, item);
+    public void add(ItemInfo item, int rank, boolean animate) {
+        if (!Folder.willAccept(item)) {
+            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);
         }
@@ -149,14 +146,14 @@
      *
      * @param item
      */
-    public void remove(WorkspaceItemInfo item, boolean animate) {
+    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<WorkspaceItemInfo> items, boolean animate) {
+    public void removeAll(List<ItemInfo> items, boolean animate) {
         contents.removeAll(items);
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onRemove(items);
@@ -164,11 +161,38 @@
         itemsChanged(animate);
     }
 
+    /**
+     * Returns the folder's contents as an ArrayList of {@link ItemInfo}. Includes
+     * {@link WorkspaceItemInfo} and {@link AppPairInfo}s.
+     */
+    @NonNull
+    @Override
+    public ArrayList<ItemInfo> getContents() {
+        return contents;
+    }
+
+    /**
+     * Returns the folder's contents as an ArrayList of {@link WorkspaceItemInfo}. Note: Does not
+     * return any {@link AppPairInfo}s contained in the folder, instead collects *their* contents
+     * and adds them to the ArrayList.
+     */
+    @Override
+    public ArrayList<WorkspaceItemInfo> getAppContents()  {
+        ArrayList<WorkspaceItemInfo> workspaceItemInfos = new ArrayList<>();
+        for (ItemInfo item : contents) {
+            if (item instanceof WorkspaceItemInfo wii) {
+                workspaceItemInfos.add(wii);
+            } else if (item instanceof AppPairInfo api) {
+                workspaceItemInfos.addAll(api.getAppContents());
+            }
+        }
+        return workspaceItemInfos;
+    }
+
     @Override
     public void onAddToDatabase(@NonNull ContentWriter writer) {
         super.onAddToDatabase(writer);
-        writer.put(LauncherSettings.Favorites.TITLE, title)
-                .put(LauncherSettings.Favorites.OPTIONS, options);
+        writer.put(LauncherSettings.Favorites.OPTIONS, options);
     }
 
     public void addListener(FolderListener listener) {
@@ -186,9 +210,11 @@
     }
 
     public interface FolderListener {
-        void onAdd(WorkspaceItemInfo item, int rank);
-        void onRemove(List<WorkspaceItemInfo> item);
+        void onAdd(ItemInfo item, int rank);
+        void onRemove(List<ItemInfo> item);
         void onItemsChanged(boolean animate);
+        void onTitleChanged(CharSequence title);
+
     }
 
     public boolean hasOption(int optionFlag) {
@@ -219,9 +245,9 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo fInfo) {
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo cInfo) {
         FolderIcon.Builder folderIcon = FolderIcon.newBuilder()
-                .setCardinality(contents.size());
+                .setCardinality(getContents().size());
         if (LabelState.SUGGESTED.equals(getLabelState())) {
             folderIcon.setLabelInfo(title.toString());
         }
@@ -261,6 +287,10 @@
         if (modelWriter != null) {
             modelWriter.updateItemInDatabase(this);
         }
+
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onTitleChanged(title);
+        }
     }
 
     /**
@@ -278,17 +308,15 @@
     public ItemInfo makeShallowCopy() {
         FolderInfo folderInfo = new FolderInfo();
         folderInfo.copyFrom(this);
-        folderInfo.contents = this.contents;
         return folderInfo;
     }
 
-    /**
-     * Returns {@link LauncherAtom.FolderIcon} wrapped as {@link LauncherAtom.ItemInfo} for logging.
-     */
-    @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto() {
-        return buildProto(null);
+    public void copyFrom(@NonNull ItemInfo info) {
+        super.copyFrom(info);
+        if (info instanceof FolderInfo fi) {
+            contents.addAll(fi.getContents());
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 86393a0..72e85c7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -94,6 +94,10 @@
      * {@link Favorites#ITEM_TYPE_APP_PAIR},
      * {@link Favorites#ITEM_TYPE_APPWIDGET} or
      * {@link Favorites#ITEM_TYPE_CUSTOM_APPWIDGET}.
+     * {@link Favorites#ITEM_TYPE_TASK}.
+     * {@link Favorites#ITEM_TYPE_QSB}.
+     * {@link Favorites#ITEM_TYPE_SEARCH_ACTION}.
+     * {@link Favorites#ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON}.
      */
     public int itemType;
 
@@ -160,6 +164,13 @@
     public CharSequence title;
 
     /**
+     * Optionally set: The appTitle might e.g. be different if {@code title} is used to
+     * display progress (e.g. Downloading..).
+     */
+    @Nullable
+    public CharSequence appTitle;
+
+    /**
      * Content description of the item.
      */
     @Nullable
@@ -338,10 +349,9 @@
 
     /**
      * Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
-     * @param fInfo
      */
     @NonNull
-    public LauncherAtom.ItemInfo buildProto(@Nullable final FolderInfo fInfo) {
+    public LauncherAtom.ItemInfo buildProto(@Nullable final CollectionInfo cInfo) {
         LauncherAtom.ItemInfo.Builder itemBuilder = getDefaultItemInfoBuilder();
         Optional<ComponentName> nullableComponent = Optional.ofNullable(getTargetComponent());
         switch (itemType) {
@@ -387,21 +397,21 @@
             default:
                 break;
         }
-        if (fInfo != null) {
+        if (cInfo != null) {
             LauncherAtom.FolderContainer.Builder folderBuilder =
                     LauncherAtom.FolderContainer.newBuilder();
             folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId);
 
-            switch (fInfo.container) {
+            switch (cInfo.container) {
                 case CONTAINER_HOTSEAT:
                 case CONTAINER_HOTSEAT_PREDICTION:
                     folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
-                            .setIndex(fInfo.screenId));
+                            .setIndex(cInfo.screenId));
                     break;
                 case CONTAINER_DESKTOP:
                     folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
-                            .setPageIndex(fInfo.screenId)
-                            .setGridX(fInfo.cellX).setGridY(fInfo.cellY));
+                            .setPageIndex(cInfo.screenId)
+                            .setGridX(cInfo.cellX).setGridY(cInfo.cellY));
                     break;
             }
             itemBuilder.setContainerInfo(ContainerInfo.newBuilder().setFolder(folderBuilder));
@@ -417,12 +427,10 @@
     @NonNull
     protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
-        UserIconInfo info = getUserInfo();
-        itemBuilder.setIsWork(info != null && info.isWork());
-        itemBuilder.setUserType(getUserType(info));
-        SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate();
-        boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0);
-        itemBuilder.setIsKidsMode(isKidsMode);
+        SettingsCache.INSTANCE.executeIfCreated(cache ->
+                itemBuilder.setIsKidsMode(cache.getValue(NAV_BAR_KIDS_MODE, 0)));
+        UserCache.INSTANCE.executeIfCreated(cache ->
+                itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
         itemBuilder.setRank(rank);
         return itemBuilder;
     }
@@ -516,15 +524,6 @@
         this.title = title;
     }
 
-    private UserIconInfo getUserInfo() {
-        UserCache userCache = UserCache.INSTANCE.getNoCreate();
-        if (userCache == null) {
-            return null;
-        }
-
-        return userCache.getUserInfo(user);
-    }
-
     private int getUserType(UserIconInfo info) {
         if (info == null) {
             return SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_UNKNOWN;
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index dc180d8..d4c25cb 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -18,15 +18,18 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.Process;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Flags;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.BitmapInfo.DrawableCreationFlags;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApiWrapper;
 
 /**
  * Represents an ItemInfo which also holds an icon.
@@ -113,6 +116,17 @@
     public static final int FLAG_NOT_PINNABLE = 1 << 13;
 
     /**
+     * Flag indicating whether the package related to the item & user corresponds to that of
+     * archived app.
+     */
+    public static final int FLAG_ARCHIVED = 1 << 14;
+
+    /**
+     * Flag indicating whether the package related to the item & user does not support resizing.
+     */
+    public static final int FLAG_NOT_RESIZEABLE = 1 << 15;
+
+    /**
      * Status associated with the system state of the underlying item. This is calculated every
      * time a new info is created and not persisted on the disk.
      */
@@ -126,7 +140,8 @@
      */
     private int mProgressLevel = 100;
 
-    protected ItemInfoWithIcon() { }
+    protected ItemInfoWithIcon() {
+    }
 
     protected ItemInfoWithIcon(ItemInfoWithIcon info) {
         super(info);
@@ -142,6 +157,29 @@
     }
 
     /**
+     * @return {@code true} if the app is pending download (0 progress) or if the app is archived
+     * and its install session is active
+     */
+    public boolean isPendingDownload() {
+        return getProgressLevel() == 0;
+    }
+
+    /**
+     * Returns true if the app corresponding to the item is archived.
+     */
+    public boolean isArchived() {
+        if (!Flags.enableSupportForArchiving()) {
+            return false;
+        }
+        return (runtimeStatusFlags & FLAG_ARCHIVED) != 0;
+    }
+
+    /** Returns true if the app is archived and doesn't have an active install session. */
+    public boolean isInactiveArchive() {
+        return isArchived() && (runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0;
+    }
+
+    /**
      * Indicates whether we're using a low res icon
      */
     public boolean usingLowResIcon() {
@@ -157,7 +195,7 @@
     public boolean isAppStartable() {
         return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0)
                 && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0)
-                    || mProgressLevel == 100);
+                || mProgressLevel == 100 || isArchived());
     }
 
     /**
@@ -166,7 +204,10 @@
      * progress.
      */
     public int getProgressLevel() {
-        if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+        if (((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0)
+                // This condition for archived apps is so that in case unarchival/update of
+                // archived app is cancelled, the state transitions back to 0% installed state.
+                || isArchived()) {
             return mProgressLevel;
         }
         return 100;
@@ -210,13 +251,32 @@
         }
     }
 
+    /**
+     * Sets whether this app info is non-resizeable.
+     */
+    public void setNonResizeable(boolean nonResizeable) {
+        if (nonResizeable) {
+            runtimeStatusFlags |= FLAG_NOT_RESIZEABLE;
+        } else {
+            runtimeStatusFlags &= ~FLAG_NOT_RESIZEABLE;
+        }
+    }
+
+    /**
+     * Returns whether this app info is resizeable.
+     */
+    public boolean isNonResizeable() {
+        return (runtimeStatusFlags & FLAG_NOT_RESIZEABLE) != 0;
+    }
+
     /** Creates an intent to that launches the app store at this app's page. */
     @Nullable
     public Intent getMarketIntent(Context context) {
         String targetPackage = getTargetPackage();
 
         return targetPackage != null
-                ? new PackageManagerHelper(context).getMarketIntent(targetPackage)
+                ? ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
+                        targetPackage, Process.myUserHandle())
                 : null;
     }
 
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index 1fbe04f..f4dda55 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -32,13 +32,11 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.util.WidgetSizes;
 
 /**
  * Represents a widget (either instantiated or about to be) in the Launcher.
@@ -143,8 +141,6 @@
      */
     private int widgetFeatures;
 
-    private boolean mHasNotifiedInitialWidgetSizeChanged;
-
     /**
      * The container from which this widget was added (e.g. widgets tray, pin widget, search)
      */
@@ -202,17 +198,6 @@
                 .put(LauncherSettings.Favorites.APPWIDGET_SOURCE, sourceContainer);
     }
 
-    /**
-     * When we bind the widget, we should notify the widget that the size has changed if we have not
-     * done so already (only really for default workspace widgets).
-     */
-    public void onBindAppWidget(Launcher launcher, AppWidgetHostView hostView) {
-        if (!mHasNotifiedInitialWidgetSizeChanged) {
-            WidgetSizes.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
-            mHasNotifiedInitialWidgetSizeChanged = true;
-        }
-    }
-
     @Override
     protected String dumpProperties() {
         return super.dumpProperties()
@@ -286,8 +271,8 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
-        LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+        LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
         return info.toBuilder()
                 .setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures))
                 .addItemAttributes(getAttribute(sourceContainer))
diff --git a/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java b/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java
new file mode 100644
index 0000000..1e7281d
--- /dev/null
+++ b/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data;
+
+import com.android.launcher3.LauncherSettings;
+
+/**
+ * Represents the Private Space Install App button in AllAppsView.
+ */
+public class PrivateSpaceInstallAppButtonInfo extends AppInfo {
+
+    public PrivateSpaceInstallAppButtonInfo() {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON;
+    }
+}
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 3ce194d..2c533ac 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -25,12 +25,14 @@
 
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ContentWriter;
 
 import java.util.Arrays;
@@ -120,6 +122,11 @@
     public WorkspaceItemInfo(ShortcutInfo shortcutInfo, Context context) {
         user = shortcutInfo.getUserHandle();
         itemType = Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+        if (Flags.privateSpaceRestrictAccessibilityDrag()) {
+            if (UserCache.INSTANCE.get(context).getUserInfo(user).isPrivate()) {
+                runtimeStatusFlags |= FLAG_NOT_PINNABLE;
+            }
+        }
         updateFromDeepShortcutInfo(shortcutInfo, context);
     }
 
@@ -148,9 +155,19 @@
 
 
     public final boolean isPromise() {
-        return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON);
+        return hasStatusFlag(FLAG_RESTORED_ICON | FLAG_AUTOINSTALL_ICON)
+                // For archived apps, promise icons are always ready to be displayed.
+                || isArchived();
     }
 
+    /**
+     * Returns true if the workspace item supports promise icon UI. There are a few cases where they
+     * are supported:
+     * 1. Icons to be restored via backup/restore.
+     * 2. Icons added as an auto-install app.
+     * 3. Icons added due to it being an active install session created by the user.
+     * 4. Icons for archived apps.
+     */
     public boolean hasPromiseIconUi() {
         return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI);
     }
@@ -172,14 +189,13 @@
             runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER;
         }
         disabledMessage = shortcutInfo.getDisabledMessage();
-        if (Utilities.ATLEAST_P
-                && shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
+        if (shortcutInfo.getDisabledReason() == ShortcutInfo.DISABLED_REASON_VERSION_LOWER) {
             runtimeStatusFlags |= FLAG_DISABLED_VERSION_LOWER;
         } else {
             runtimeStatusFlags &= ~FLAG_DISABLED_VERSION_LOWER;
         }
 
-        Person[] persons = ApiWrapper.getPersons(shortcutInfo);
+        Person[] persons = ApiWrapper.INSTANCE.get(context).getPersons(shortcutInfo);
         personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY
             : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);
     }
diff --git a/src/com/android/launcher3/notification/NotificationContainer.java b/src/com/android/launcher3/notification/NotificationContainer.java
deleted file mode 100644
index 7cc9ad3..0000000
--- a/src/com/android/launcher3/notification/NotificationContainer.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.notification;
-
-import static com.android.app.animation.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.FloatProperty;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.popup.PopupContainerWithArrow;
-import com.android.launcher3.touch.BaseSwipeDetector;
-import com.android.launcher3.touch.OverScroll;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Class to manage the notification UI in a {@link PopupContainerWithArrow}.
- *
- * - Has two {@link NotificationMainView} that represent the top two notifications
- * - Handles dismissing a notification
- */
-public class NotificationContainer extends FrameLayout implements SingleAxisSwipeDetector.Listener {
-
-    private static final FloatProperty<NotificationContainer> DRAG_TRANSLATION_X =
-            new FloatProperty<NotificationContainer>("notificationProgress") {
-                @Override
-                public void setValue(NotificationContainer view, float transX) {
-                    view.setDragTranslationX(transX);
-                }
-
-                @Override
-                public Float get(NotificationContainer view) {
-                    return view.mDragTranslationX;
-                }
-            };
-
-    private static final Rect sTempRect = new Rect();
-
-    private final SingleAxisSwipeDetector mSwipeDetector;
-    private final List<NotificationInfo> mNotificationInfos = new ArrayList<>();
-    private boolean mIgnoreTouch = false;
-
-    private final ObjectAnimator mContentTranslateAnimator;
-    private float mDragTranslationX = 0;
-
-    private final NotificationMainView mPrimaryView;
-    private final NotificationMainView mSecondaryView;
-    private PopupContainerWithArrow mPopupContainer;
-
-    public NotificationContainer(Context context) {
-        this(context, null, 0);
-    }
-
-    public NotificationContainer(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationContainer(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        mSwipeDetector = new SingleAxisSwipeDetector(getContext(), this, HORIZONTAL);
-        mSwipeDetector.setDetectableScrollConditions(SingleAxisSwipeDetector.DIRECTION_BOTH, false);
-        mContentTranslateAnimator = ObjectAnimator.ofFloat(this, DRAG_TRANSLATION_X, 0);
-
-        mPrimaryView = (NotificationMainView) View.inflate(getContext(),
-                R.layout.notification_content, null);
-        mSecondaryView = (NotificationMainView) View.inflate(getContext(),
-                R.layout.notification_content, null);
-        mSecondaryView.setAlpha(0);
-
-        addView(mSecondaryView);
-        addView(mPrimaryView);
-
-    }
-
-    public void setPopupView(PopupContainerWithArrow popupView) {
-        mPopupContainer = popupView;
-    }
-
-    /**
-     * Returns true if we should intercept the swipe.
-     */
-    public boolean onInterceptSwipeEvent(MotionEvent ev) {
-        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            sTempRect.set(getLeft(), getTop(), getRight(), getBottom());
-            mIgnoreTouch = !sTempRect.contains((int) ev.getX(), (int) ev.getY());
-            if (!mIgnoreTouch) {
-                mPopupContainer.getParent().requestDisallowInterceptTouchEvent(true);
-            }
-        }
-        if (mIgnoreTouch) {
-            return false;
-        }
-        if (mPrimaryView.getNotificationInfo() == null) {
-            // The notification hasn't been populated yet.
-            return false;
-        }
-
-        mSwipeDetector.onTouchEvent(ev);
-        return mSwipeDetector.isDraggingOrSettling();
-    }
-
-    /**
-     * Returns true when we should handle the swipe.
-     */
-    public boolean onSwipeEvent(MotionEvent ev) {
-        if (mIgnoreTouch) {
-            return false;
-        }
-        if (mPrimaryView.getNotificationInfo() == null) {
-            // The notification hasn't been populated yet.
-            return false;
-        }
-        return mSwipeDetector.onTouchEvent(ev);
-    }
-
-    /**
-     * Applies the list of @param notificationInfos to this container.
-     */
-    public void applyNotificationInfos(final List<NotificationInfo> notificationInfos) {
-        mNotificationInfos.clear();
-        if (notificationInfos.isEmpty()) {
-            mPrimaryView.applyNotificationInfo(null);
-            mSecondaryView.applyNotificationInfo(null);
-            return;
-        }
-        mNotificationInfos.addAll(notificationInfos);
-
-        NotificationInfo mainNotification = notificationInfos.get(0);
-        mPrimaryView.applyNotificationInfo(mainNotification);
-        mSecondaryView.applyNotificationInfo(notificationInfos.size() > 1
-                ? notificationInfos.get(1)
-                : null);
-    }
-
-    /**
-     * Trims the notifications.
-     * @param notificationKeys List of all valid notification keys.
-     */
-    public void trimNotifications(final List<String> notificationKeys) {
-        Iterator<NotificationInfo> iterator = mNotificationInfos.iterator();
-        while (iterator.hasNext()) {
-            if (!notificationKeys.contains(iterator.next().notificationKey)) {
-                iterator.remove();
-            }
-        }
-
-        NotificationInfo primaryInfo = mNotificationInfos.size() > 0
-                ? mNotificationInfos.get(0)
-                : null;
-        NotificationInfo secondaryInfo = mNotificationInfos.size() > 1
-                ? mNotificationInfos.get(1)
-                : null;
-
-        mPrimaryView.applyNotificationInfo(primaryInfo);
-        mSecondaryView.applyNotificationInfo(secondaryInfo);
-
-        mPrimaryView.onPrimaryDrag(0);
-        mSecondaryView.onSecondaryDrag(0);
-    }
-
-    private void setDragTranslationX(float translationX) {
-        mDragTranslationX = translationX;
-
-        float progress = translationX / getWidth();
-        mPrimaryView.onPrimaryDrag(progress);
-        if (mSecondaryView.getNotificationInfo() == null) {
-            mSecondaryView.setAlpha(0f);
-        } else {
-            mSecondaryView.onSecondaryDrag(progress);
-        }
-    }
-
-    // SingleAxisSwipeDetector.Listener's
-    @Override
-    public void onDragStart(boolean start, float startDisplacement) {
-        mPopupContainer.showArrow(false);
-    }
-
-    @Override
-    public boolean onDrag(float displacement) {
-        if (!mPrimaryView.canChildBeDismissed()) {
-            displacement = OverScroll.dampedScroll(displacement, getWidth());
-        }
-
-        float progress = displacement / getWidth();
-        mPrimaryView.onPrimaryDrag(progress);
-        if (mSecondaryView.getNotificationInfo() == null) {
-            mSecondaryView.setAlpha(0f);
-        } else {
-            mSecondaryView.onSecondaryDrag(progress);
-        }
-        mContentTranslateAnimator.cancel();
-        return true;
-    }
-
-    @Override
-    public void onDragEnd(float velocity) {
-        final boolean willExit;
-        final float endTranslation;
-        final float startTranslation = mPrimaryView.getTranslationX();
-        final float width = getWidth();
-
-        if (!mPrimaryView.canChildBeDismissed()) {
-            willExit = false;
-            endTranslation = 0;
-        } else if (mSwipeDetector.isFling(velocity)) {
-            willExit = true;
-            endTranslation = velocity < 0 ? -width : width;
-        } else if (Math.abs(startTranslation) > width / 2f) {
-            willExit = true;
-            endTranslation = (startTranslation < 0 ? -width : width);
-        } else {
-            willExit = false;
-            endTranslation = 0;
-        }
-
-        long duration = BaseSwipeDetector.calculateDuration(velocity,
-                (endTranslation - startTranslation) / width);
-
-        mContentTranslateAnimator.removeAllListeners();
-        mContentTranslateAnimator.setDuration(duration)
-                .setInterpolator(scrollInterpolatorForVelocity(velocity));
-        mContentTranslateAnimator.setFloatValues(startTranslation, endTranslation);
-
-        NotificationMainView current = mPrimaryView;
-        mContentTranslateAnimator.addListener(new AnimationSuccessListener() {
-            @Override
-            public void onAnimationSuccess(Animator animator) {
-                mSwipeDetector.finishedScrolling();
-                if (willExit) {
-                    current.onChildDismissed();
-                }
-                mPopupContainer.showArrow(true);
-            }
-        });
-        mContentTranslateAnimator.start();
-    }
-
-    /**
-     * Animates the background color to a new color.
-     * @param color The color to change to.
-     * @param animatorSetOut The AnimatorSet where we add the color animator to.
-     */
-    public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
-        mPrimaryView.updateBackgroundColor(color, animatorSetOut);
-        mSecondaryView.updateBackgroundColor(color, animatorSetOut);
-    }
-
-    /**
-     * Updates the header with a new @param notificationCount.
-     */
-    public void updateHeader(int notificationCount) {
-        mPrimaryView.updateHeader(notificationCount);
-        mSecondaryView.updateHeader(notificationCount - 1);
-    }
-}
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
deleted file mode 100644
index f4468fd..0000000
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2017 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.notification;
-
-import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP;
-import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
-import static com.android.launcher3.Utilities.allowBGLaunch;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_LAUNCH_TAP;
-
-import android.app.ActivityOptions;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
-import android.service.notification.StatusBarNotification;
-import android.view.View;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.dot.DotInfo;
-import com.android.launcher3.graphics.IconPalette;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.popup.PopupDataProvider;
-import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.views.ActivityContext;
-
-/**
- * An object that contains relevant information from a {@link StatusBarNotification}. This should
- * only be created when we need to show the notification contents on the UI; until then, a
- * {@link DotInfo} with only the notification key should
- * be passed around, and then this can be constructed using the StatusBarNotification from
- * {@link NotificationListener#getNotificationsForKeys(java.util.List)}.
- */
-public class NotificationInfo implements View.OnClickListener {
-
-    public final PackageUserKey packageUserKey;
-    public final String notificationKey;
-    public final CharSequence title;
-    public final CharSequence text;
-    public final PendingIntent intent;
-    public final boolean autoCancel;
-    public final boolean dismissable;
-
-    private final ItemInfo mItemInfo;
-    private Drawable mIconDrawable;
-    private int mIconColor;
-    private boolean mIsIconLarge;
-
-    /**
-     * Extracts the data that we need from the StatusBarNotification.
-     */
-    public NotificationInfo(Context context, StatusBarNotification statusBarNotification,
-            ItemInfo itemInfo) {
-        packageUserKey = PackageUserKey.fromNotification(statusBarNotification);
-        notificationKey = statusBarNotification.getKey();
-        Notification notification = statusBarNotification.getNotification();
-        title = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
-        text = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
-
-        int iconType = notification.getBadgeIconType();
-        // Load the icon. Since it is backed by ashmem, we won't copy the entire bitmap
-        // into our process as long as we don't touch it and it exists in systemui.
-        Icon icon = iconType == Notification.BADGE_ICON_SMALL ? null : notification.getLargeIcon();
-        if (icon == null) {
-            // Use the small icon.
-            icon = notification.getSmallIcon();
-            mIconDrawable = icon == null ? null : icon.loadDrawable(context);
-            mIconColor = statusBarNotification.getNotification().color;
-            mIsIconLarge = false;
-        } else {
-            // Use the large icon.
-            mIconDrawable = icon.loadDrawable(context);
-            mIsIconLarge = true;
-        }
-        if (mIconDrawable == null) {
-            mIconDrawable = LauncherAppState.getInstance(context).getIconCache()
-                    .getDefaultIcon(statusBarNotification.getUser()).newIcon(context);
-        }
-        intent = notification.contentIntent;
-        autoCancel = (notification.flags & Notification.FLAG_AUTO_CANCEL) != 0;
-        dismissable = (notification.flags & Notification.FLAG_ONGOING_EVENT) == 0;
-        this.mItemInfo = itemInfo;
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (intent == null) {
-            return;
-        }
-        final ActivityContext context = ActivityContext.lookupContext(view.getContext());
-        ActivityOptions options = allowBGLaunch(ActivityOptions.makeClipRevealAnimation(
-                view, 0, 0, view.getWidth(), view.getHeight()));
-        try {
-            intent.send(null, 0, null, null, null, null, options.toBundle());
-            context.getStatsLogManager().logger().withItemInfo(mItemInfo)
-                    .log(LAUNCHER_NOTIFICATION_LAUNCH_TAP);
-        } catch (PendingIntent.CanceledException e) {
-            e.printStackTrace();
-        }
-        if (autoCancel) {
-            PopupDataProvider popupDataProvider = context.getPopupDataProvider();
-            if (popupDataProvider != null) {
-                popupDataProvider.cancelNotification(notificationKey);
-            }
-        }
-        AbstractFloatingView.closeOpenViews(
-                context, true, TYPE_ACTION_POPUP | TYPE_TASKBAR_ALL_APPS);
-    }
-
-    public Drawable getIconForBackground(Context context, int background) {
-        if (mIsIconLarge) {
-            // Only small icons should be tinted.
-            return mIconDrawable;
-        }
-        mIconColor = IconPalette.resolveContrastColor(context, mIconColor, background);
-        Drawable icon = mIconDrawable.mutate();
-        // DrawableContainer ignores the color filter if it's already set, so clear it first to
-        // get it set and invalidated properly.
-        icon.setTintList(null);
-        icon.setTint(mIconColor);
-        return icon;
-    }
-}
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
index 1dda3df..4115b3d 100644
--- a/src/com/android/launcher3/notification/NotificationKeyData.java
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -26,13 +26,10 @@
 import com.android.launcher3.Utilities;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * The key data associated with the notification, used to determine what to include
  * in dots and stub popup views before they are populated.
- *
- * @see NotificationInfo for the full data used when populating the stub views.
  */
 public class NotificationKeyData {
     public final String notificationKey;
@@ -56,15 +53,6 @@
                         Notification.EXTRA_PEOPLE_LIST)));
     }
 
-    public static List<String> extractKeysOnly(
-            @NonNull List<NotificationKeyData> notificationKeys) {
-        List<String> keysOnly = new ArrayList<>(notificationKeys.size());
-        for (NotificationKeyData notificationKeyData : notificationKeys) {
-            keysOnly.add(notificationKeyData.notificationKey);
-        }
-        return keysOnly;
-    }
-
     private static String[] extractPersonKeyOnly(@Nullable ArrayList<Person> people) {
         if (people == null || people.isEmpty()) {
             return Utilities.EMPTY_STRING_ARRAY;
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 04eb38a..836ea4a 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -34,7 +34,6 @@
 import android.util.Log;
 import android.util.Pair;
 
-import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
@@ -64,8 +63,7 @@
     private static final int MSG_NOTIFICATION_POSTED = 1;
     private static final int MSG_NOTIFICATION_REMOVED = 2;
     private static final int MSG_NOTIFICATION_FULL_REFRESH = 3;
-    private static final int MSG_CANCEL_NOTIFICATION = 4;
-    private static final int MSG_RANKING_UPDATE = 5;
+    private static final int MSG_RANKING_UPDATE = 4;
 
     private static NotificationListener sNotificationListenerInstance = null;
     private static final ArraySet<NotificationsChangedListener> sNotificationsChangedListeners =
@@ -81,9 +79,6 @@
     /** Maps keys to their corresponding current group key */
     private final Map<String, String> mNotificationGroupKeyMap = new HashMap<>();
 
-    /** The last notification key that was dismissed from launcher UI */
-    private String mLastKeyDismissedByLauncher;
-
     private SettingsCache mSettingsCache;
     private SettingsCache.OnChangeListener mNotificationSettingsChangedListener;
 
@@ -93,7 +88,7 @@
         sNotificationListenerInstance = this;
     }
 
-    public static @Nullable NotificationListener getInstanceIfConnected() {
+    private static @Nullable NotificationListener getInstanceIfConnected() {
         return sIsConnected ? sNotificationListenerInstance : null;
     }
 
@@ -139,17 +134,9 @@
                 if (notificationGroup != null) {
                     notificationGroup.removeChildKey(key);
                     if (notificationGroup.isEmpty()) {
-                        if (key.equals(mLastKeyDismissedByLauncher)) {
-                            // Only cancel the group notification if launcher dismissed the
-                            // last child.
-                            cancelNotification(notificationGroup.getGroupSummaryKey());
-                        }
                         mNotificationGroupMap.remove(sbn.getGroupKey());
                     }
                 }
-                if (key.equals(mLastKeyDismissedByLauncher)) {
-                    mLastKeyDismissedByLauncher = null;
-                }
                 return true;
             }
             case MSG_NOTIFICATION_FULL_REFRESH:
@@ -164,11 +151,6 @@
 
                 mUiHandler.obtainMessage(message.what, activeNotifications).sendToTarget();
                 return true;
-            case MSG_CANCEL_NOTIFICATION: {
-                mLastKeyDismissedByLauncher = (String) message.obj;
-                cancelNotification(mLastKeyDismissedByLauncher);
-                return true;
-            }
             case MSG_RANKING_UPDATE: {
                 String[] keys = ((RankingMap) message.obj).getOrderedKeys();
                 for (StatusBarNotification sbn : getActiveNotificationsSafely(keys)) {
@@ -272,14 +254,6 @@
         mWorkerHandler.obtainMessage(MSG_RANKING_UPDATE, rankingMap).sendToTarget();
     }
 
-    /**
-     * Cancels a notification
-     */
-    @AnyThread
-    public void cancelNotificationFromLauncher(String key) {
-        mWorkerHandler.obtainMessage(MSG_CANCEL_NOTIFICATION, key).sendToTarget();
-    }
-
     @WorkerThread
     private void updateGroupKeyIfNecessary(StatusBarNotification sbn) {
         String childKey = sbn.getKey();
@@ -315,15 +289,6 @@
     }
 
     /**
-     * This makes a potentially expensive binder call and should be run on a background thread.
-     */
-    @WorkerThread
-    public List<StatusBarNotification> getNotificationsForKeys(List<NotificationKeyData> keys) {
-        return Arrays.asList(getActiveNotificationsSafely(
-                keys.stream().map(n -> n.notificationKey).toArray(String[]::new)));
-    }
-
-    /**
      * Returns true for notifications that have an intent and are not headers for grouped
      * notifications and should be shown in the notification popup.
      */
diff --git a/src/com/android/launcher3/notification/NotificationMainView.java b/src/com/android/launcher3/notification/NotificationMainView.java
deleted file mode 100644
index ecd018b..0000000
--- a/src/com/android/launcher3/notification/NotificationMainView.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright (C) 2017 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.notification;
-
-import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.Utilities.mapToRange;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DISMISSED;
-
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.graphics.Outline;
-import android.graphics.Rect;
-import android.graphics.drawable.GradientDrawable;
-import android.os.Build;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.popup.PopupDataProvider;
-import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.ActivityContext;
-
-/**
- * A {@link android.widget.FrameLayout} that contains a single notification,
- * e.g. icon + title + text.
- */
-@TargetApi(Build.VERSION_CODES.N)
-public class NotificationMainView extends LinearLayout {
-
-    // This is used only to track the notification view, so that it can be properly logged.
-    public static final ItemInfo NOTIFICATION_ITEM_INFO = new ItemInfo();
-
-    // Value when the primary notification main view will be gone (zero alpha).
-    private static final float PRIMARY_GONE_PROGRESS = 0.7f;
-    private static final float PRIMARY_MIN_PROGRESS = 0.40f;
-    private static final float PRIMARY_MAX_PROGRESS = 0.60f;
-    private static final float SECONDARY_MIN_PROGRESS = 0.30f;
-    private static final float SECONDARY_MAX_PROGRESS = 0.50f;
-    private static final float SECONDARY_CONTENT_MAX_PROGRESS = 0.6f;
-
-    private NotificationInfo mNotificationInfo;
-    private int mBackgroundColor;
-    private TextView mTitleView;
-    private TextView mTextView;
-    private View mIconView;
-
-    private View mHeader;
-    private View mMainView;
-
-    private TextView mHeaderCount;
-    private final Rect mOutline = new Rect();
-
-    // Space between notifications during swipe
-    private final int mNotificationSpace;
-    private final int mMaxTransX;
-    private final int mMaxElevation;
-
-    private final GradientDrawable mBackground;
-
-    public NotificationMainView(Context context) {
-        this(context, null, 0);
-    }
-
-    public NotificationMainView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NotificationMainView(Context context, AttributeSet attrs, int defStyle) {
-        this(context, attrs, defStyle, 0);
-    }
-
-    public NotificationMainView(Context context, AttributeSet attrs, int defStyle, int defStylRes) {
-        super(context, attrs, defStyle, defStylRes);
-
-        float outlineRadius = Themes.getDialogCornerRadius(context);
-
-        mBackground = new GradientDrawable();
-        mBackground.setColor(Themes.getAttrColor(context, R.attr.popupColorPrimary));
-        mBackground.setCornerRadius(outlineRadius);
-        setBackground(mBackground);
-
-        mMaxElevation = getResources().getDimensionPixelSize(R.dimen.deep_shortcuts_elevation);
-        setElevation(mMaxElevation);
-
-        mMaxTransX = getResources().getDimensionPixelSize(R.dimen.notification_max_trans);
-        mNotificationSpace = getResources().getDimensionPixelSize(R.dimen.notification_space);
-
-        setClipToOutline(true);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                outline.setRoundRect(mOutline, outlineRadius);
-            }
-        });
-    }
-
-    /**
-     * Updates the header text.
-     * @param notificationCount The number of notifications.
-     */
-    public void updateHeader(int notificationCount) {
-        final String text;
-        final int visibility;
-        if (notificationCount <= 1) {
-            text = "";
-            visibility = View.INVISIBLE;
-        } else {
-            text = String.valueOf(notificationCount);
-            visibility = View.VISIBLE;
-
-        }
-        mHeaderCount.setText(text);
-        mHeaderCount.setVisibility(visibility);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        ViewGroup textAndBackground = findViewById(R.id.text_and_background);
-        mTitleView = textAndBackground.findViewById(R.id.title);
-        mTextView = textAndBackground.findViewById(R.id.text);
-        mIconView = findViewById(R.id.popup_item_icon);
-        mHeaderCount = findViewById(R.id.notification_count);
-
-        mHeader = findViewById(R.id.header);
-        mMainView = findViewById(R.id.main_view);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        mOutline.set(0, 0, getWidth(), getHeight());
-        invalidateOutline();
-    }
-
-    private void updateBackgroundColor(int color) {
-        mBackgroundColor = color;
-        mBackground.setColor(color);
-        if (mNotificationInfo != null) {
-            mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
-                    mBackgroundColor));
-        }
-    }
-
-    /**
-     * Animates the background color to a new color.
-     * @param color The color to change to.
-     * @param animatorSetOut The AnimatorSet where we add the color animator to.
-     */
-    public void updateBackgroundColor(int color, AnimatorSet animatorSetOut) {
-        int oldColor = mBackgroundColor;
-        ValueAnimator colors = ValueAnimator.ofArgb(oldColor, color);
-        colors.addUpdateListener(valueAnimator -> {
-            int newColor = (int) valueAnimator.getAnimatedValue();
-            updateBackgroundColor(newColor);
-        });
-        animatorSetOut.play(colors);
-    }
-
-    /**
-     * Sets the content of this view, animating it after a new icon shifts up if necessary.
-     */
-    public void applyNotificationInfo(NotificationInfo notificationInfo) {
-        mNotificationInfo = notificationInfo;
-        if (notificationInfo == null) {
-            return;
-        }
-        NotificationListener listener = NotificationListener.getInstanceIfConnected();
-        if (listener != null) {
-            listener.setNotificationsShown(new String[] {mNotificationInfo.notificationKey});
-        }
-        CharSequence title = mNotificationInfo.title;
-        CharSequence text = mNotificationInfo.text;
-        if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(text)) {
-            mTitleView.setText(title.toString());
-            mTextView.setText(text.toString());
-        } else {
-            mTitleView.setMaxLines(2);
-            mTitleView.setText(TextUtils.isEmpty(title) ? text.toString() : title.toString());
-            mTextView.setVisibility(GONE);
-        }
-        mIconView.setBackground(mNotificationInfo.getIconForBackground(getContext(),
-                mBackgroundColor));
-        if (mNotificationInfo.intent != null) {
-            setOnClickListener(mNotificationInfo);
-        }
-
-        // Add a stub ItemInfo so that logging populates the correct container and item types
-        // instead of DEFAULT_CONTAINERTYPE and DEFAULT_ITEMTYPE, respectively.
-        setTag(NOTIFICATION_ITEM_INFO);
-    }
-
-    /**
-     * Sets the alpha of only the child views.
-     */
-    public void setContentAlpha(float alpha) {
-        mHeader.setAlpha(alpha);
-        mMainView.setAlpha(alpha);
-    }
-
-    /**
-     * Sets the translation of only the child views.
-     */
-    public void setContentTranslationX(float transX) {
-        mHeader.setTranslationX(transX);
-        mMainView.setTranslationX(transX);
-    }
-
-    /**
-     * Updates the alpha, content alpha, and elevation of this view.
-     *
-     * @param progress Range from [0, 1] or [-1, 0]
-     *                 When 0: Full alpha
-     *                 When 1/-1: zero alpha
-     */
-    public void onPrimaryDrag(float progress) {
-        float absProgress = Math.abs(progress);
-        final int width = getWidth();
-
-        float min = PRIMARY_MIN_PROGRESS;
-        float max = PRIMARY_MAX_PROGRESS;
-
-        if (absProgress < min) {
-            setAlpha(1f);
-            setContentAlpha(1);
-            setElevation(mMaxElevation);
-        } else if (absProgress < max) {
-            setAlpha(1f);
-            setContentAlpha(mapToRange(absProgress, min, max, 1f, 0f, LINEAR));
-            setElevation(Utilities.mapToRange(absProgress, min, max, mMaxElevation, 0, LINEAR));
-        } else {
-            setAlpha(mapToRange(absProgress, max, PRIMARY_GONE_PROGRESS, 1f, 0f, LINEAR));
-            setContentAlpha(0f);
-            setElevation(0f);
-        }
-
-        setTranslationX(width * progress);
-    }
-
-    /**
-     * Updates the alpha, content alpha, elevation, and clipping of this view.
-     * @param progress Range from [0, 1] or [-1, 0]
-      *                 When 0: Smallest clipping, zero alpha
-      *                 When 1/-1: Full clip, full alpha
-     */
-    public void onSecondaryDrag(float progress) {
-        final float absProgress = Math.abs(progress);
-
-        float min = SECONDARY_MIN_PROGRESS;
-        float max = SECONDARY_MAX_PROGRESS;
-        float contentMax = SECONDARY_CONTENT_MAX_PROGRESS;
-
-        if (absProgress < min) {
-            setAlpha(0f);
-            setContentAlpha(0);
-            setElevation(0f);
-        } else if (absProgress < max) {
-            setAlpha(mapToRange(absProgress, min, max, 0, 1f, LINEAR));
-            setContentAlpha(0f);
-            setElevation(0f);
-        } else {
-            setAlpha(1f);
-            setContentAlpha(absProgress > contentMax
-                    ? 1f
-                    : mapToRange(absProgress, max, contentMax, 0, 1f, LINEAR));
-            setElevation(Utilities.mapToRange(absProgress, max, 1, 0, mMaxElevation, LINEAR));
-        }
-
-        final int width = getWidth();
-        int crop = (int) (width * absProgress);
-        int space = (int) (absProgress > PRIMARY_GONE_PROGRESS
-                ? mapToRange(absProgress, PRIMARY_GONE_PROGRESS, 1f, mNotificationSpace, 0, LINEAR)
-                : mNotificationSpace);
-        if (progress < 0) {
-            mOutline.left = Math.max(0, getWidth() - crop + space);
-            mOutline.right = getWidth();
-        } else {
-            mOutline.right = Math.min(getWidth(), crop - space);
-            mOutline.left = 0;
-        }
-
-        float contentTransX = mMaxTransX * (1f - absProgress);
-        setContentTranslationX(progress < 0
-                ? contentTransX
-                : -contentTransX);
-        invalidateOutline();
-    }
-
-    public @Nullable NotificationInfo getNotificationInfo() {
-        return mNotificationInfo;
-    }
-
-    public boolean canChildBeDismissed() {
-        return mNotificationInfo != null && mNotificationInfo.dismissable;
-    }
-
-    public void onChildDismissed() {
-        ActivityContext activityContext = ActivityContext.lookupContext(getContext());
-        PopupDataProvider popupDataProvider = activityContext.getPopupDataProvider();
-        if (popupDataProvider == null) {
-            return;
-        }
-        popupDataProvider.cancelNotification(mNotificationInfo.notificationKey);
-        activityContext.getStatsLogManager().logger().log(LAUNCHER_NOTIFICATION_DISMISSED);
-    }
-}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 30156c8..0640bf3 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -27,10 +27,12 @@
     void setMarkersCount(int numMarkers);
 
     /**
-     * Sets flag to indicate when the screens are in the process of binding so that we don't animate
-     * during that period.
+     * 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
+     * those periods.</p>
      */
-    default void setAreScreensBinding(boolean areScreensBinding, boolean isTwoPanels) {
+    default void setPauseScroll(boolean pause, boolean isTwoPanels) {
         // No-op by default
     }
 
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index fd1b64f..e44ea1d 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -130,7 +130,7 @@
      */
     private float mCurrentPosition;
     private float mFinalPosition;
-    private boolean mAreScreensBinding;
+    private boolean mIsScrollPaused;
     private boolean mIsTwoPanels;
     private ObjectAnimator mAnimator;
     private @Nullable ObjectAnimator mAlphaAnimator;
@@ -153,7 +153,7 @@
 
         mPaginationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mPaginationPaint.setStyle(Style.FILL);
-        mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
+        mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.pageIndicatorDotColor));
         mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
         mCircleGap = DOT_GAP_FACTOR * mDotRadius;
         setOutlineProvider(new MyOutlineProver());
@@ -172,7 +172,7 @@
         }
 
         // Skip scroll update during binding. We will update it when binding completes.
-        if (mAreScreensBinding) {
+        if (mIsScrollPaused) {
             return;
         }
 
@@ -365,19 +365,26 @@
     @Override
     public void setMarkersCount(int numMarkers) {
         mNumPages = numMarkers;
+
+        // If the last page gets removed we want to go to the previous page.
+        if (mNumPages > 0 && mNumPages == mActivePage) {
+            mActivePage--;
+            CURRENT_POSITION.set(this, (float) mActivePage);
+        }
+
         requestLayout();
     }
 
     @Override
-    public void setAreScreensBinding(boolean areScreensBinding, boolean isTwoPanels) {
+    public void setPauseScroll(boolean pause, boolean isTwoPanels) {
         mIsTwoPanels = isTwoPanels;
 
         // Reapply correct current position which was skipped during setScroll.
-        if (mAreScreensBinding && !areScreensBinding) {
+        if (mIsScrollPaused && !pause) {
             CURRENT_POSITION.set(this, (float) mActivePage);
         }
 
-        mAreScreensBinding = areScreensBinding;
+        mIsScrollPaused = pause;
     }
 
     @Override
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index cb3c16c..e66f496 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -22,7 +22,6 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
-import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
 
@@ -30,9 +29,9 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.util.IntArray;
@@ -41,6 +40,7 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -51,7 +51,8 @@
 /**
  * Utility class to tracking install sessions
  */
-public class InstallSessionHelper {
+@SuppressWarnings("NewApi")
+public class InstallSessionHelper implements SafeCloseable {
 
     @NonNull
     private static final String LOG = "InstallSessionHelper";
@@ -88,6 +89,9 @@
         mLauncherApps = context.getSystemService(LauncherApps.class);
     }
 
+    @Override
+    public void close() { }
+
     @WorkerThread
     @NonNull
     private IntSet getPromiseIconIds() {
@@ -129,7 +133,7 @@
     public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) {
         for (SessionInfo info : getAllVerifiedSessions()) {
             boolean match = pkg.equals(info.getAppPackageName());
-            if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) {
+            if (!user.equals(getUserHandle(info))) {
                 match = false;
             }
             if (match) {
@@ -167,7 +171,7 @@
         synchronized (mSessionVerifiedMap) {
             if (!mSessionVerifiedMap.containsKey(pkg)) {
                 boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg)
-                        || new PackageManagerHelper(mAppContext)
+                        || PackageManagerHelper.INSTANCE.get(mAppContext)
                                 .getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
                 mSessionVerifiedMap.put(pkg, hasSystemFlag);
             }
@@ -177,9 +181,8 @@
 
     @NonNull
     public List<SessionInfo> getAllVerifiedSessions() {
-        List<SessionInfo> list = new ArrayList<>(Utilities.ATLEAST_Q
-                ? Objects.requireNonNull(mLauncherApps).getAllPackageInstallerSessions()
-                : mInstaller.getAllSessions());
+        List<SessionInfo> list = new ArrayList<>(
+                Objects.requireNonNull(mLauncherApps).getAllPackageInstallerSessions());
         Iterator<SessionInfo> it = list.iterator();
         while (it.hasNext()) {
             if (verify(it.next()) == null) {
@@ -212,14 +215,19 @@
      */
     @WorkerThread
     void tryQueuePromiseAppIcon(@Nullable final PackageInstaller.SessionInfo sessionInfo) {
-        if (SessionCommitReceiver.isEnabled(mAppContext)
+        if (sessionInfo != null
+                && SessionCommitReceiver.isEnabled(mAppContext, getUserHandle(sessionInfo))
                 && verifySessionInfo(sessionInfo)
                 && !promiseIconAddedForId(sessionInfo.getSessionId())) {
-            FileLog.d(LOG, "Adding package name to install queue: "
-                    + sessionInfo.getAppPackageName());
+            // In case of unarchival, we do not want to add a workspace promise icon if one is
+            // not already present. For general app installations however, we do support it.
+            if (!Flags.enableSupportForArchiving() || !sessionInfo.isUnarchival()) {
+                FileLog.d(LOG, "Adding package name to install queue: "
+                        + sessionInfo.getAppPackageName());
 
-            ItemInstallQueue.INSTANCE.get(mAppContext)
-                    .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
+                ItemInstallQueue.INSTANCE.get(mAppContext)
+                        .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
+            }
 
             getPromiseIconIds().add(sessionInfo.getSessionId());
             updatePromiseIconPrefs();
@@ -227,11 +235,17 @@
     }
 
     public boolean verifySessionInfo(@Nullable final PackageInstaller.SessionInfo sessionInfo) {
+        // For archived apps we always want to show promise icons and the checks below don't apply.
+        if (Flags.enableSupportForArchiving() && sessionInfo != null
+                && sessionInfo.isUnarchival()) {
+            return true;
+        }
+
         return verify(sessionInfo) != null
                 && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
                 && sessionInfo.getAppIcon() != null
                 && !TextUtils.isEmpty(sessionInfo.getAppLabel())
-                && !new PackageManagerHelper(mAppContext).isAppInstalled(
+                && !PackageManagerHelper.INSTANCE.get(mAppContext).isAppInstalled(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
     }
 
@@ -244,6 +258,6 @@
     }
 
     public static UserHandle getUserHandle(@NonNull final SessionInfo info) {
-        return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
+        return info.getUser();
     }
 }
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index 41908d3..24d58f3 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -31,11 +31,14 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.Flags;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.util.PackageUserKey;
 
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
+@SuppressWarnings("NewApi")
 @WorkerThread
 public class InstallSessionTracker extends PackageInstaller.SessionCallback {
 
@@ -77,6 +80,13 @@
         }
 
         helper.tryQueuePromiseAppIcon(sessionInfo);
+
+        if (Flags.enableSupportForArchiving() && sessionInfo != null
+                && sessionInfo.isUnarchival()) {
+            // For archived apps, icon could already be present on the workspace. To make sure
+            // the icon state is updated, we send a change event.
+            callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(sessionInfo));
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 4661fd4..b7b557d 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -17,7 +17,6 @@
 package com.android.launcher3.pm;
 
 import static com.android.launcher3.Utilities.ATLEAST_U;
-import static com.android.launcher3.uioverrides.ApiWrapper.queryAllUsers;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.content.Context;
@@ -25,11 +24,18 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.UserBadgeDrawable;
+import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -76,6 +82,9 @@
     @NonNull
     private Map<UserHandle, UserIconInfo> mUserToSerialMap;
 
+    @NonNull
+    private Map<UserHandle, List<String>> mUserToPreInstallAppMap;
+
     private UserCache(Context context) {
         mContext = context;
         mUserToSerialMap = Collections.emptyMap();
@@ -114,7 +123,21 @@
 
     @WorkerThread
     private void updateCache() {
-        mUserToSerialMap = queryAllUsers(mContext);
+        mUserToSerialMap = ApiWrapper.INSTANCE.get(mContext).queryAllUsers();
+        mUserToPreInstallAppMap = fetchPreInstallApps();
+    }
+
+    @WorkerThread
+    private Map<UserHandle, List<String>> fetchPreInstallApps() {
+        Map<UserHandle, List<String>> userToPreInstallApp = new ArrayMap<>();
+        mUserToSerialMap.forEach((userHandle, userIconInfo) -> {
+            // Fetch only for private profile, as other profiles have no usages yet.
+            List<String> preInstallApp = userIconInfo.isPrivate()
+                    ? ApiWrapper.INSTANCE.get(mContext).getPreInstalledSystemPackages(userHandle)
+                    : new ArrayList<>();
+            userToPreInstallApp.put(userHandle, preInstallApp);
+        });
+        return userToPreInstallApp;
     }
 
     /**
@@ -154,10 +177,34 @@
                 .orElse(Process.myUserHandle());
     }
 
+    @VisibleForTesting
+    public void putToCache(UserHandle userHandle, UserIconInfo info) {
+        mUserToSerialMap.put(userHandle, info);
+    }
+
     /**
      * @see UserManager#getUserProfiles()
      */
     public List<UserHandle> getUserProfiles() {
         return List.copyOf(mUserToSerialMap.keySet());
     }
+
+    /**
+     * Returns the pre-installed apps for a user.
+     */
+    @NonNull
+    public List<String> getPreInstallApps(UserHandle user) {
+        List<String> preInstallApp = mUserToPreInstallAppMap.get(user);
+        return preInstallApp == null ? new ArrayList<>() : preInstallApp;
+    }
+
+    /**
+     * Get a non-themed {@link UserBadgeDrawable} based on the provided {@link UserHandle}.
+     */
+    @Nullable
+    public static UserBadgeDrawable getBadgeDrawable(Context context, UserHandle userHandle) {
+        return (UserBadgeDrawable) BitmapInfo.LOW_RES_INFO.withFlags(UserCache.getInstance(context)
+                        .getUserInfo(userHandle).applyBitmapInfoFlags(FlagOp.NO_OP))
+                .getBadgeDrawable(context, false /* isThemed */);
+    }
 }
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index e3314d4..4d4a8f7 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -636,10 +636,10 @@
         return getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
     }
 
-    protected AnimatorSet getOpenCloseAnimator(boolean isOpening, int scaleDuration,
-            int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
-            Interpolator interpolator) {
-
+    /**
+     * Sets X and Y pivots for the view animation considering arrow position.
+     */
+    protected void setPivotForOpenCloseAnimation() {
         int arrowCenter = mArrowOffsetHorizontal + mArrowWidth / 2;
         if (mIsArrowRotated) {
             setPivotX(mIsLeftAligned ? 0f : getMeasuredWidth());
@@ -648,6 +648,14 @@
             setPivotX(mIsLeftAligned ? arrowCenter : getMeasuredWidth() - arrowCenter);
             setPivotY(mIsAboveIcon ? getMeasuredHeight() : 0f);
         }
+    }
+
+
+    protected AnimatorSet getOpenCloseAnimator(boolean isOpening, int scaleDuration,
+            int fadeStartDelay, int fadeDuration, int childFadeStartDelay, int childFadeDuration,
+            Interpolator interpolator) {
+
+        setPivotForOpenCloseAnimation();
 
         float[] alphaValues = isOpening ? new float[] {0, 1} : new float[] {1, 0};
         float[] scaleValues = isOpening ? new float[] {0.5f, 1.02f} : new float[] {1f, 0.5f};
diff --git a/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java b/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
index c0a04b1..89b5ba1 100644
--- a/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
+++ b/src/com/android/launcher3/popup/LauncherPopupLiveUpdateHandler.java
@@ -87,9 +87,4 @@
             }
         }
     }
-
-    @Override
-    protected void showPopupContainerForIcon(BubbleTextView originalIcon) {
-        PopupContainerWithArrow.showForIcon(originalIcon);
-    }
 }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 934d43b..1c9db17 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -17,9 +17,9 @@
 package com.android.launcher3.popup;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
-import static com.android.launcher3.Utilities.ATLEAST_P;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
+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;
 
@@ -45,6 +45,7 @@
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -54,6 +55,7 @@
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
@@ -205,17 +207,21 @@
                 .collect(Collectors.toList());
         container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
                 R.layout.popup_container, launcher.getDragLayer(), false);
-        container.configureForLauncher(launcher);
+        container.configureForLauncher(launcher, item);
         container.populateAndShowRows(icon, deepShortcutCount, systemShortcuts);
         launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
         container.requestFocus();
         return container;
     }
 
-    private void configureForLauncher(Launcher launcher) {
+    private void configureForLauncher(Launcher launcher, ItemInfo itemInfo) {
         addOnAttachStateChangeListener(new LauncherPopupLiveUpdateHandler(
                 launcher, (PopupContainerWithArrow<Launcher>) this));
-        mPopupItemDragHandler = new LauncherPopupItemDragHandler(launcher, this);
+        if (!Flags.privateSpaceRestrictItemDrag()
+                || !(itemInfo instanceof ItemInfoWithIcon itemInfoWithIcon)
+                || (itemInfoWithIcon.runtimeStatusFlags & FLAG_NOT_PINNABLE) == 0) {
+            mPopupItemDragHandler = new LauncherPopupItemDragHandler(launcher, this);
+        }
         mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(launcher);
         launcher.getDragController().addDragListener(this);
     }
@@ -248,10 +254,7 @@
      * Animates and loads shortcuts on background thread for this popup container
      */
     private void loadAppShortcuts(ItemInfo originalItemInfo) {
-
-        if (ATLEAST_P) {
-            setAccessibilityPaneTitle(getTitleForAccessibility());
-        }
+        setAccessibilityPaneTitle(getTitleForAccessibility());
         mOriginalIcon.setForceHideDot(true);
         // All views are added. Animate layout from now on.
         setLayoutTransition(new LayoutTransition());
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 44e3dd6..fb463f7 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -31,17 +31,19 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.ShortcutUtil;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -73,7 +75,6 @@
 
     private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
         mNotificationDotsChangeListener.accept(updatedDots);
-        mChangeListener.onNotificationDotsUpdated(updatedDots);
     }
 
     @Override
@@ -98,7 +99,6 @@
                 mPackageUserToDotInfos.remove(removedPackageUserKey);
             }
             updateNotificationDots(removedPackageUserKey::equals);
-            trimNotifications(mPackageUserToDotInfos);
         }
     }
 
@@ -136,11 +136,6 @@
         if (!updatedDots.isEmpty()) {
             updateNotificationDots(updatedDots::containsKey);
         }
-        trimNotifications(updatedDots);
-    }
-
-    private void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) {
-        mChangeListener.trimNotifications(updatedDots);
     }
 
     public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
@@ -169,26 +164,23 @@
         if (dotInfo == null) {
             return null;
         }
-        List<NotificationKeyData> notifications = getNotificationsForItem(
-                info, dotInfo.getNotificationKeys());
-        if (notifications.isEmpty()) {
-            return null;
-        }
-        return dotInfo;
-    }
 
-    public @NonNull List<NotificationKeyData> getNotificationKeysForItem(ItemInfo info) {
-        DotInfo dotInfo = getDotInfoForItem(info);
-        return dotInfo == null ? Collections.EMPTY_LIST
-                : getNotificationsForItem(info, dotInfo.getNotificationKeys());
-    }
-
-    public void cancelNotification(String notificationKey) {
-        NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
-        if (notificationListener == null) {
-            return;
+        // If the item represents a pinned shortcut, ensure that there is a notification
+        // for this shortcut
+        String shortcutId = ShortcutUtil.getShortcutIdIfPinnedShortcut(info);
+        if (shortcutId == null) {
+            return dotInfo;
         }
-        notificationListener.cancelNotificationFromLauncher(notificationKey);
+        String[] personKeys = ShortcutUtil.getPersonKeysIfPinnedShortcut(info);
+        return (dotInfo.getNotificationKeys().stream().anyMatch(notification -> {
+            if (notification.shortcutId != null) {
+                return notification.shortcutId.equals(shortcutId);
+            }
+            if (notification.personKeysFromNotification.length != 0) {
+                return Arrays.equals(notification.personKeysFromNotification, personKeys);
+            }
+            return false;
+        })) ? dotInfo : null;
     }
 
     /**
@@ -229,6 +221,34 @@
                 .collect(Collectors.toList());
     }
 
+    /** Returns the recommended widgets mapped by their category. */
+    @NonNull
+    public Map<WidgetRecommendationCategory, List<WidgetItem>> getCategorizedRecommendedWidgets() {
+        Map<ComponentKey, WidgetItem> allWidgetItems = mAllWidgets.stream()
+                .filter(entry -> entry instanceof WidgetsListContentEntry)
+                .flatMap(entry -> entry.mWidgets.stream())
+                .distinct()
+                .collect(Collectors.toMap(
+                        widget -> new ComponentKey(widget.componentName, widget.user),
+                        Function.identity()
+                ));
+        return mRecommendedWidgets.stream()
+                .filter(itemInfo -> itemInfo instanceof PendingAddWidgetInfo
+                        && ((PendingAddWidgetInfo) itemInfo).recommendationCategory != null)
+                .collect(Collectors.groupingBy(
+                        it -> ((PendingAddWidgetInfo) it).recommendationCategory,
+                        Collectors.collectingAndThen(
+                                Collectors.toList(),
+                                list -> list.stream()
+                                        .map(it -> allWidgetItems.get(
+                                                new ComponentKey(it.getTargetComponent(),
+                                                        it.user)))
+                                        .filter(Objects::nonNull)
+                                        .collect(Collectors.toList())
+                        )
+                ));
+    }
+
     public List<WidgetItem> getWidgetsForPackageUser(PackageUserKey packageUserKey) {
         return mAllWidgets.stream()
                 .filter(row -> row instanceof WidgetsListContentEntry
@@ -247,53 +267,18 @@
                 .orElse(null);
     }
 
-    /**
-     * Returns a list of notifications that are relevant to given ItemInfo.
-     */
-    public static @NonNull List<NotificationKeyData> getNotificationsForItem(
-            @NonNull ItemInfo info, @NonNull List<NotificationKeyData> notifications) {
-        String shortcutId = ShortcutUtil.getShortcutIdIfPinnedShortcut(info);
-        if (shortcutId == null) {
-            return notifications;
-        }
-        String[] personKeys = ShortcutUtil.getPersonKeysIfPinnedShortcut(info);
-        return notifications.stream().filter((NotificationKeyData notification) -> {
-                    if (notification.shortcutId != null) {
-                        return notification.shortcutId.equals(shortcutId);
-                    }
-                    if (notification.personKeysFromNotification.length != 0) {
-                        return Arrays.equals(notification.personKeysFromNotification, personKeys);
-                    }
-                    return false;
-                }).collect(Collectors.toList());
-    }
-
     public void dump(String prefix, PrintWriter writer) {
         writer.println(prefix + "PopupDataProvider:");
         writer.println(prefix + "\tmPackageUserToDotInfos:" + mPackageUserToDotInfos);
     }
 
-    /**
-     * Tells the listener that the system shortcuts have been updated, causing them to be redrawn.
-     */
-    public void redrawSystemShortcuts() {
-        mChangeListener.onSystemShortcutsUpdated();
-    }
-
     public interface PopupDataChangeListener {
 
         PopupDataChangeListener INSTANCE = new PopupDataChangeListener() { };
 
-        default void onNotificationDotsUpdated(Predicate<PackageUserKey> updatedDots) { }
-
-        default void trimNotifications(Map<PackageUserKey, DotInfo> updatedDots) { }
-
         default void onWidgetsBound() { }
 
         /** A callback to get notified when recommended widgets are bound. */
         default void onRecommendedWidgetsBound() { }
-
-        /** A callback to get notified when system shortcuts have been updated. */
-        default void onSystemShortcutsUpdated() { }
     }
 }
diff --git a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
index 9d6f2a5..4c94f94 100644
--- a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
+++ b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.view.View;
 
-import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.views.ActivityContext;
 
 /**
@@ -56,12 +55,4 @@
             popupDataProvider.setChangeListener(null);
         }
     }
-
-    @Override
-    public void onSystemShortcutsUpdated() {
-        mPopupContainerWithArrow.close(true);
-        showPopupContainerForIcon(mPopupContainerWithArrow.getOriginalIcon());
-    }
-
-    protected abstract void showPopupContainerForIcon(BubbleTextView originalIcon);
 }
diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java
index eab0969..0860ae5 100644
--- a/src/com/android/launcher3/popup/RemoteActionShortcut.java
+++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java
@@ -20,13 +20,11 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
-import android.annotation.TargetApi;
 import android.app.ActivityOptions;
 import android.app.PendingIntent;
 import android.app.RemoteAction;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Build;
 import android.util.Log;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -35,23 +33,22 @@
 import android.widget.Toast;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.views.ActivityContext;
 
 import java.lang.ref.WeakReference;
 
-@TargetApi(Build.VERSION_CODES.Q)
-public class RemoteActionShortcut extends SystemShortcut<BaseDraggingActivity> {
+public class RemoteActionShortcut<T extends Context & ActivityContext> extends SystemShortcut<T> {
     private static final String TAG = "RemoteActionShortcut";
     private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE;
 
     private final RemoteAction mAction;
 
     public RemoteActionShortcut(RemoteAction action,
-            BaseDraggingActivity activity, ItemInfo itemInfo, View originalView) {
-        super(0, R.id.action_remote_action_shortcut, activity, itemInfo, originalView);
+            T context, ItemInfo itemInfo, View originalView) {
+        super(0, R.id.action_remote_action_shortcut, context, itemInfo, originalView);
         mAction = action;
     }
 
@@ -83,7 +80,7 @@
         mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
                 .log(LAUNCHER_SYSTEM_SHORTCUT_PAUSE_TAP);
 
-        final WeakReference<BaseDraggingActivity> weakTarget = new WeakReference<>(mTarget);
+        final WeakReference<T> weakTarget = new WeakReference<>(mTarget);
         final String actionIdentity = mAction.getTitle() + ", "
                 + mItemInfo.getTargetComponent().getPackageName();
 
@@ -98,7 +95,7 @@
                             mItemInfo.getTargetComponent().getPackageName()),
                     (pendingIntent, intent, resultCode, resultData, resultExtras) -> {
                         if (DEBUG) Log.d(TAG, "Action is complete: " + actionIdentity);
-                        final BaseDraggingActivity target = weakTarget.get();
+                        final T target = weakTarget.get();
                         if (resultData != null && !resultData.isEmpty()) {
                             Log.e(TAG, "Remote action returned result: " + actionIdentity
                                     + " : " + resultData);
@@ -119,9 +116,4 @@
                     .show();
         }
     }
-
-    @Override
-    public boolean isLeftGroup() {
-        return true;
-    }
 }
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 436aa51..575052c 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -84,11 +84,12 @@
      * @param width        of the arrow.
      * @param height       of the arrow.
      * @param radius       of the tip of the arrow.
-     * @param isPointingLeft or not.
+     * @param isHorizontal or not.
+     * @param isLeftOrTop  or not.
      * @param color        to draw the triangle.
      */
-    public RoundedArrowDrawable(float width, float height, float radius, boolean isPointingLeft,
-            int color) {
+    private RoundedArrowDrawable(float width, float height, float radius, boolean isHorizontal,
+            boolean isLeftOrTop, int color) {
         mPath = new Path();
         mPaint = new Paint();
         mPaint.setColor(color);
@@ -98,10 +99,47 @@
         // Make the drawable with the triangle pointing down...
         addDownPointingRoundedTriangleToPath(width, height, radius, mPath);
 
-        // ... then rotate it to the side it needs to point.
-        Matrix pathTransform = new Matrix();
-        pathTransform.setRotate(isPointingLeft ? 90 : -90, width * 0.5f, height * 0.5f);
-        mPath.transform(pathTransform);
+        if (isHorizontal || isLeftOrTop) {
+            // ... then rotate it to the side it needs to point.
+            Matrix pathTransform = new Matrix();
+            int rotationAngle;
+            if (isHorizontal) {
+                rotationAngle = isLeftOrTop ? 90 : -90;
+            } else {
+                // it could only be vertical arrow pointing up
+                rotationAngle = 180;
+            }
+            pathTransform.setRotate(rotationAngle, width * 0.5f, height * 0.5f);
+            mPath.transform(pathTransform);
+        }
+    }
+
+    /**
+     * factory method for an arrow that points to the left or right.
+     *
+     * @param width          of the arrow.
+     * @param height         of the arrow.
+     * @param radius         of the tip of the arrow.
+     * @param isPointingLeft or not.
+     * @param color          to draw the triangle.
+     */
+    public static RoundedArrowDrawable createHorizontalRoundedArrow(float width, float height,
+            float radius, boolean isPointingLeft, int color) {
+        return new RoundedArrowDrawable(width, height, radius, true, isPointingLeft, color);
+    }
+
+    /**
+     * factory method for an arrow that points to the left or right.
+     *
+     * @param width        of the arrow.
+     * @param height       of the arrow.
+     * @param radius       of the tip of the arrow.
+     * @param isPointingUp or not.
+     * @param color        to draw the triangle.
+     */
+    public static RoundedArrowDrawable createVerticalRoundedArrow(float width, float height,
+            float radius, boolean isPointingUp, int color) {
+        return new RoundedArrowDrawable(width, height, radius, false, isPointingUp, color);
     }
 
     @Override
@@ -129,6 +167,14 @@
         mPaint.setColorFilter(colorFilter);
     }
 
+    /**
+     * Set shadow layer to internal {@link Paint#setShadowLayer(float, float, float, int) paint}
+     * object
+     */
+    public void setShadowLayer(float shadowBlur, float dx, float dy, int shadowColor) {
+        mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
+    }
+
     private static void addDownPointingRoundedTriangleToPath(float width, float height,
             float radius, Path path) {
         // Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 69bba69..6005573 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -1,33 +1,46 @@
 package com.android.launcher3.popup;
 
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
 
 import android.app.ActivityOptions;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
+import android.os.Process;
+import android.os.UserHandle;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.AbstractFloatingViewHelper;
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
+import com.android.launcher3.SecondaryDropTarget;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.PrivateProfileManager;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.InstantAppResolver;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.WidgetsBottomSheet;
 
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -35,12 +48,12 @@
  * onClickListener that depends on the item that the shortcut services.
  *
  * Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
- * @param <T>
+ *
+ * @param <T> extends {@link ActivityContext}
  */
-public abstract class SystemShortcut<T extends Context & ActivityContext> extends ItemInfo
+public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo
         implements View.OnClickListener {
 
-    private static final String TAG = SystemShortcut.class.getSimpleName();
     private final int mIconResId;
     protected final int mLabelResId;
     protected int mAccessibilityActionId;
@@ -49,48 +62,33 @@
     protected final ItemInfo mItemInfo;
     protected final View mOriginalView;
 
-    /**
-     * Indicates if it's invokable or not through some disabled UI
-     */
-    private boolean isEnabled = true;
+    private final AbstractFloatingViewHelper mAbstractFloatingViewHelper;
 
     public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo,
             View originalView) {
+        this(iconResId, labelResId, target, itemInfo, originalView,
+                new AbstractFloatingViewHelper());
+    }
+
+    public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo,
+            View originalView, AbstractFloatingViewHelper abstractFloatingViewHelper) {
         mIconResId = iconResId;
         mLabelResId = labelResId;
         mAccessibilityActionId = labelResId;
         mTarget = target;
         mItemInfo = itemInfo;
         mOriginalView = originalView;
-    }
-
-    public SystemShortcut(SystemShortcut<T> other) {
-        mIconResId = other.mIconResId;
-        mLabelResId = other.mLabelResId;
-        mAccessibilityActionId = other.mAccessibilityActionId;
-        mTarget = other.mTarget;
-        mItemInfo = other.mItemInfo;
-        mOriginalView = other.mOriginalView;
-    }
-
-    /**
-     * Should be in the left group of icons in app's context menu header.
-     */
-    public boolean isLeftGroup() {
-        return false;
+        mAbstractFloatingViewHelper = abstractFloatingViewHelper;
     }
 
     public void setIconAndLabelFor(View iconView, TextView labelView) {
         iconView.setBackgroundResource(mIconResId);
-        iconView.setEnabled(isEnabled);
         labelView.setText(mLabelResId);
-        labelView.setEnabled(isEnabled);
     }
 
     public void setIconAndContentDescriptionFor(ImageView view) {
         view.setImageResource(mIconResId);
         view.setContentDescription(view.getContext().getText(mLabelResId));
-        view.setEnabled(isEnabled);
     }
 
     public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) {
@@ -98,36 +96,29 @@
                 mAccessibilityActionId, context.getText(mLabelResId));
     }
 
-    public void setEnabled(boolean enabled) {
-        isEnabled = enabled;
-    }
-
-    public boolean isEnabled() {
-        return isEnabled;
-    }
-
     public boolean hasHandlerForAction(int action) {
         return mAccessibilityActionId == action;
     }
 
-    public interface Factory<T extends Context & ActivityContext> {
+    public interface Factory<T extends ActivityContext> {
 
-        @Nullable SystemShortcut<T> getShortcut(T activity, ItemInfo itemInfo, View originalView);
+        @Nullable
+        SystemShortcut<T> getShortcut(T context, ItemInfo itemInfo, @NonNull View originalView);
     }
 
-    public static final Factory<Launcher> WIDGETS = (launcher, itemInfo, originalView) -> {
+    public static final Factory<ActivityContext> WIDGETS = (context, itemInfo, originalView) -> {
         if (itemInfo.getTargetComponent() == null) return null;
         final List<WidgetItem> widgets =
-                launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(
+                context.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(
                         itemInfo.getTargetComponent().getPackageName(), itemInfo.user));
         if (widgets.isEmpty()) {
             return null;
         }
-        return new Widgets(launcher, itemInfo, originalView);
+        return new Widgets(context, itemInfo, originalView);
     };
 
-    public static class Widgets extends SystemShortcut<Launcher> {
-        public Widgets(Launcher target, ItemInfo itemInfo, View originalView) {
+    public static class Widgets<T extends ActivityContext> extends SystemShortcut<T> {
+        public Widgets(T target, ItemInfo itemInfo, @NonNull View originalView) {
             super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo,
                     originalView);
         }
@@ -144,14 +135,14 @@
         }
     }
 
-    public static final Factory<BaseDraggingActivity> APP_INFO = AppInfo::new;
+    public static final Factory<ActivityContext> APP_INFO = AppInfo::new;
 
-    public static class AppInfo<T extends Context & ActivityContext> extends SystemShortcut<T> {
+    public static class AppInfo<T extends ActivityContext> extends SystemShortcut<T> {
 
         @Nullable
         private SplitAccessibilityInfo mSplitA11yInfo;
 
-        public AppInfo(T target, ItemInfo itemInfo, View originalView) {
+        public AppInfo(T target, ItemInfo itemInfo, @NonNull View originalView) {
             super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target,
                     itemInfo, originalView);
         }
@@ -188,10 +179,10 @@
 
         @Override
         public void onClick(View view) {
-            dismissTaskMenuView(mTarget);
+            dismissTaskMenuView();
             Rect sourceBounds = Utilities.getViewBounds(view);
-            new PackageManagerHelper(mTarget).startDetailsActivityForInfo(
-                    mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle());
+            PackageManagerHelper.startDetailsActivityForInfo(view.getContext(), mItemInfo,
+                    sourceBounds, ActivityOptions.makeBasic().toBundle());
             mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo)
                     .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP);
         }
@@ -210,8 +201,81 @@
         }
     }
 
-    public static final Factory<BaseDraggingActivity> INSTALL =
+    public static final Factory<ActivityContext> PRIVATE_PROFILE_INSTALL =
+            (context, itemInfo, originalView) -> {
+                if (originalView == null) {
+                    return null;
+                }
+                if (itemInfo.getTargetComponent() == null
+                        || !(itemInfo instanceof com.android.launcher3.model.data.AppInfo)
+                        || !itemInfo.getContainerInfo().hasAllAppsContainer()
+                        || !Process.myUserHandle().equals(itemInfo.user)) {
+                    return null;
+                }
+
+                PrivateProfileManager privateProfileManager =
+                        context.getAppsView().getPrivateProfileManager();
+                if (privateProfileManager == null || !privateProfileManager.isEnabled()) {
+                    return null;
+                }
+
+                UserHandle privateProfileUser = privateProfileManager.getProfileUser();
+                if (privateProfileUser == null) {
+                    return null;
+                }
+                // Do not show shortcut if an app is already installed to the space
+                ComponentName targetComponent = itemInfo.getTargetComponent();
+                if (context.getAppsView().getAppsStore().getApp(
+                        new ComponentKey(targetComponent, privateProfileUser)) != null) {
+                    return null;
+                }
+
+                // Do not show shortcut for settings
+                String[] packagesToSkip =
+                        originalView.getContext().getResources()
+                                .getStringArray(R.array.skip_private_profile_shortcut_packages);
+                if (Arrays.asList(packagesToSkip).contains(targetComponent.getPackageName())) {
+                    return null;
+                }
+
+                return new InstallToPrivateProfile<>(
+                        context, itemInfo, originalView, privateProfileUser);
+            };
+
+    static class InstallToPrivateProfile<T extends ActivityContext> extends SystemShortcut<T> {
+        UserHandle mSpaceUser;
+
+        InstallToPrivateProfile(T target, ItemInfo itemInfo, @NonNull View originalView,
+                UserHandle spaceUser) {
+            // TODO(b/302666597): update icon once available
+            super(
+                    R.drawable.ic_install_to_private,
+                    R.string.install_private_system_shortcut_label,
+                    target,
+                    itemInfo,
+                    originalView);
+            mSpaceUser = spaceUser;
+        }
+
+        @Override
+        public void onClick(View view) {
+            Intent intent =
+                    ApiWrapper.INSTANCE.get(view.getContext()).getAppMarketActivityIntent(
+                            mItemInfo.getTargetComponent().getPackageName(), mSpaceUser);
+            mTarget.startActivitySafely(view, intent, mItemInfo);
+            AbstractFloatingView.closeAllOpenViews(mTarget);
+            mTarget.getStatsLogManager()
+                    .logger()
+                    .withItemInfo(mItemInfo)
+                    .log(LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP);
+        }
+    }
+
+    public static final Factory<ActivityContext> INSTALL =
             (activity, itemInfo, originalView) -> {
+                if (originalView == null) {
+                    return null;
+                }
                 boolean supportsWebUI = (itemInfo instanceof WorkspaceItemInfo)
                         && ((WorkspaceItemInfo) itemInfo).hasStatusFlag(
                         WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI);
@@ -219,33 +283,102 @@
                 if (itemInfo instanceof com.android.launcher3.model.data.AppInfo) {
                     com.android.launcher3.model.data.AppInfo
                             appInfo = (com.android.launcher3.model.data.AppInfo) itemInfo;
-                    isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo);
+                    isInstantApp = InstantAppResolver.newInstance(
+                            originalView.getContext()).isInstantApp(appInfo);
                 }
                 boolean enabled = supportsWebUI || isInstantApp;
                 if (!enabled) {
                     return null;
                 }
                 return new Install(activity, itemInfo, originalView);
-    };
+            };
 
-    public static class Install extends SystemShortcut<BaseDraggingActivity> {
+    public static class Install<T extends ActivityContext> extends SystemShortcut<T> {
 
-        public Install(BaseDraggingActivity target, ItemInfo itemInfo, View originalView) {
+        public Install(T target, ItemInfo itemInfo, @NonNull View originalView) {
             super(R.drawable.ic_install_no_shadow, R.string.install_drop_target_label,
                     target, itemInfo, originalView);
         }
 
         @Override
         public void onClick(View view) {
-            Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent(
-                    mItemInfo.getTargetComponent().getPackageName());
+            Intent intent = ApiWrapper.INSTANCE.get(view.getContext()).getAppMarketActivityIntent(
+                    mItemInfo.getTargetComponent().getPackageName(), Process.myUserHandle());
             mTarget.startActivitySafely(view, intent, mItemInfo);
             AbstractFloatingView.closeAllOpenViews(mTarget);
         }
     }
 
-    public static <T extends Context & ActivityContext> void dismissTaskMenuView(T activity) {
-        AbstractFloatingView.closeOpenViews(activity, true,
-            AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
+    public static final Factory<ActivityContext> DONT_SUGGEST_APP =
+            (activity, itemInfo, originalView) -> {
+                if (!itemInfo.isPredictedItem()) {
+                    return null;
+                }
+                return new DontSuggestApp<>(activity, itemInfo, originalView);
+            };
+
+    private static class DontSuggestApp<T extends ActivityContext> extends SystemShortcut<T> {
+        DontSuggestApp(T target, ItemInfo itemInfo, View originalView) {
+            super(R.drawable.ic_block_no_shadow, R.string.dismiss_prediction_label, target,
+                    itemInfo, originalView);
+        }
+
+        @Override
+        public void onClick(View view) {
+            dismissTaskMenuView();
+            mTarget.getStatsLogManager().logger()
+                    .withItemInfo(mItemInfo)
+                    .log(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP);
+        }
+    }
+
+    public static final Factory<ActivityContext> UNINSTALL_APP =
+            (activityContext, itemInfo, originalView) -> {
+                if (originalView == null) {
+                    return null;
+                }
+                if (!Flags.enablePrivateSpace()) {
+                    return null;
+                }
+                if (!UserCache.INSTANCE.get(originalView.getContext()).getUserInfo(
+                        itemInfo.user).isPrivate()) {
+                    // If app is not Private Space app.
+                    return null;
+                }
+                ComponentName cn = SecondaryDropTarget.getUninstallTarget(originalView.getContext(),
+                        itemInfo);
+                if (cn == null) {
+                    // If component name is null, don't show uninstall shortcut.
+                    // System apps will have component name as null.
+                    return null;
+                }
+                return new UninstallApp(activityContext, itemInfo, originalView, cn);
+            };
+
+    private static class UninstallApp<T extends ActivityContext> extends SystemShortcut<T> {
+        @NonNull ComponentName mComponentName;
+
+        UninstallApp(T target, ItemInfo itemInfo, @NonNull View originalView,
+                @NonNull ComponentName cn) {
+            super(R.drawable.ic_uninstall_no_shadow, R.string.uninstall_drop_target_label, target,
+                    itemInfo, originalView);
+            mComponentName = cn;
+
+        }
+
+        @Override
+        public void onClick(View view) {
+            dismissTaskMenuView();
+            SecondaryDropTarget.performUninstall(view.getContext(), mComponentName, mItemInfo);
+            mTarget.getStatsLogManager()
+                    .logger()
+                    .withItemInfo(mItemInfo)
+                    .log(LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP);
+        }
+    }
+
+    protected void dismissTaskMenuView() {
+        mAbstractFloatingViewHelper.closeOpenViews(mTarget, true,
+                AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
     }
 }
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 30958d9..b992a92 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -109,7 +109,7 @@
         UserManagerState ums = new UserManagerState();
         ums.init(UserCache.INSTANCE.get(context),
                 context.getSystemService(UserManager.class));
-        LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums);
+        LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, null);
         IntSet deletedShortcuts = new IntSet();
 
         while (lc.moveToNext()) {
@@ -152,7 +152,12 @@
             }
 
             ShortcutInfo info = infoBuilder.build();
-            if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+            try {
+                if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+                    deletedShortcuts.add(lc.id);
+                    continue;
+                }
+            } catch (Exception e) {
                 deletedShortcuts.add(lc.id);
                 continue;
             }
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index dc8cd3a..a4ff29f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -18,11 +18,16 @@
 
 import static android.os.Process.myUserHandle;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
 import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
 import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
 import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
 import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
 import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
 
@@ -46,30 +51,35 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherFiles;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DeviceGridState;
 import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDbController;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LogConfig;
 
+import java.io.File;
 import java.io.InvalidObjectException;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -83,13 +93,15 @@
 
     private static final String TAG = "RestoreDbTask";
     public static final String RESTORED_DEVICE_TYPE = "restored_task_pending";
+    public static final String FIRST_LOAD_AFTER_RESTORE_KEY = "first_load_after_restore";
 
     private static final String INFO_COLUMN_NAME = "name";
     private static final String INFO_COLUMN_DEFAULT_VALUE = "dflt_value";
 
     public static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
     public static final String APPWIDGET_IDS = "appwidget_ids";
-    private static final String[] DB_COLUMNS_TO_LOG = {"profileId", "title", "itemType", "screen",
+    @VisibleForTesting
+    public static final String[] DB_COLUMNS_TO_LOG = {"profileId", "title", "itemType", "screen",
             "container", "cellX", "cellY", "spanX", "spanY", "intent", "appWidgetProvider",
             "appWidgetId", "restored"};
 
@@ -113,7 +125,66 @@
         // executed again.
         LauncherPrefs.get(context).removeSync(RESTORE_DEVICE);
 
-        idp.reinitializeAfterRestore(context);
+        if (Flags.enableNarrowGridRestore()) {
+            String oldPhoneFileName = idp.dbFile;
+            List<String> previousDbs = existingDbs();
+            removeOldDBs(context, oldPhoneFileName);
+            // The idp before this contains data about the old phone, after this it becomes the idp
+            // of the current phone.
+            idp.reset(context);
+            trySettingPreviousGidAsCurrent(context, idp, oldPhoneFileName, previousDbs);
+        } else {
+            idp.reinitializeAfterRestore(context);
+        }
+    }
+
+
+    /**
+     * Try setting the gird used in the previous phone to the new one. If the current device doesn't
+     * support the previous grid option it will not be set.
+     */
+    private static void trySettingPreviousGidAsCurrent(Context context, InvariantDeviceProfile idp,
+            String oldPhoneDbFileName, List<String> previousDbs) {
+        InvariantDeviceProfile.GridOption oldPhoneGridOption = idp.getGridOptionFromFileName(
+                context, oldPhoneDbFileName);
+        // The grid option could be null if current phone doesn't support the previous db.
+        if (oldPhoneGridOption != null) {
+            /* If the user only used the default db on the previous phone and the new default db is
+             * bigger than or equal to the previous one, then keep the new default db */
+            if (previousDbs.size() == 1 && oldPhoneGridOption.numColumns <= idp.numColumns
+                    && oldPhoneGridOption.numRows <= idp.numRows) {
+                /* Keep the user in default grid */
+                return;
+            }
+            /*
+             * Here we are setting the previous db as the current one.
+             */
+            idp.setCurrentGrid(context, oldPhoneGridOption.name);
+        }
+    }
+
+    /**
+     * Returns a list of paths of the existing launcher dbs.
+     */
+    private static List<String> existingDbs() {
+        // At this point idp.dbFile contains the name of the dbFile from the previous phone
+        return LauncherFiles.GRID_DB_FILES.stream()
+                .filter(dbName -> new File(dbName).exists())
+                .toList();
+    }
+
+    /**
+     * Only keep the last database used on the previous device.
+     */
+    private static void removeOldDBs(Context context, String oldPhoneDbFileName) {
+        // At this point idp.dbFile contains the name of the dbFile from the previous phone
+        LauncherFiles.GRID_DB_FILES.stream()
+                .filter(dbName -> !dbName.equals(oldPhoneDbFileName))
+                .forEach(dbName -> {
+                    if (context.getDatabasePath(dbName).delete()) {
+                        FileLog.d(TAG, "Removed old grid db file: " + dbName);
+                    }
+                });
     }
 
     private static boolean performRestore(Context context, ModelDbController controller) {
@@ -121,8 +192,11 @@
         FileLog.d(TAG, "performRestore: starting restore from db");
         try (SQLiteTransaction t = new SQLiteTransaction(db)) {
             RestoreDbTask task = new RestoreDbTask();
-            task.sanitizeDB(context, controller, db, new BackupManager(context));
-            task.restoreAppWidgetIdsIfExists(context, controller);
+            BackupManager backupManager = new BackupManager(context);
+            LauncherRestoreEventLogger restoreEventLogger =
+                    LauncherRestoreEventLogger.Companion.newInstance(context);
+            task.sanitizeDB(context, controller, db, backupManager, restoreEventLogger);
+            task.restoreAppWidgetIdsIfExists(context, controller, restoreEventLogger);
             t.commit();
             return true;
         } catch (Exception e) {
@@ -145,7 +219,8 @@
      */
     @VisibleForTesting
     protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
-            BackupManager backupManager) throws Exception {
+            BackupManager backupManager, LauncherRestoreEventLogger restoreEventLogger)
+            throws Exception {
         logFavoritesTable(db, "Old Launcher Database before sanitizing:", null, null);
         // Primary user ids
         long myProfileId = controller.getSerialNumberForUser(myUserHandle());
@@ -184,6 +259,9 @@
         Arrays.fill(args, "?");
         final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
         logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
+        if (enableLauncherBrMetricsFixed()) {
+            reportUnrestoredProfiles(db, where, profileIds, restoreEventLogger);
+        }
         int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
         FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
 
@@ -311,9 +389,6 @@
      */
     private UserHandle getUserForAncestralSerialNumber(BackupManager backupManager,
             long ancestralSerialNumber) {
-        if (!Utilities.ATLEAST_Q) {
-            return null;
-        }
         return backupManager.getUserForAncestralSerialNumber(ancestralSerialNumber);
     }
 
@@ -340,23 +415,27 @@
      * Marks the DB state as pending restoration
      */
     public static void setPending(Context context) {
-        FileLog.d(TAG, "Restore data received through full backup");
-        LauncherPrefs.get(context)
-                .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType()));
+        DeviceGridState deviceGridState = new DeviceGridState(context);
+        FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
+        LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
+        if (enableLauncherBrMetricsFixed()) {
+            LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
+        }
     }
 
     @WorkerThread
     @VisibleForTesting
-    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) {
+    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller,
+            LauncherRestoreEventLogger restoreEventLogger) {
         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,
+            restoreAppWidgetIds(context, controller, restoreEventLogger,
                     IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
                     IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
                     host);
         } else {
-            FileLog.d(TAG, "No app widget ids were received from backup to restore.");
+            FileLog.d(TAG, "Did not receive new app widget id map during Launcher restore");
         }
 
         lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
@@ -367,10 +446,13 @@
      */
     @WorkerThread
     private void restoreAppWidgetIds(Context context, ModelDbController controller,
-            int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+            LauncherRestoreEventLogger launcherRestoreEventLogger, int[] oldWidgetIds,
+            int[] newWidgetIds, @NonNull AppWidgetHost host) {
+        if (!WIDGETS_ENABLED) {
             FileLog.e(TAG, "Skipping widget ID remap as widgets not supported");
             host.deleteHost();
+            launcherRestoreEventLogger.logFavoritesItemsRestoreFailed(Favorites.ITEM_TYPE_APPWIDGET,
+                    oldWidgetIds.length, RestoreError.WIDGETS_DISABLED);
             return;
         }
         if (!RestoreDbTask.isPending(context)) {
@@ -394,7 +476,7 @@
         logDatabaseWidgetInfo(controller);
 
         for (int i = 0; i < oldWidgetIds.length; i++) {
-            FileLog.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
+            FileLog.i(TAG, "migrating appWidgetId: " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
 
             final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
             final int state;
@@ -434,15 +516,17 @@
                         FileLog.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
                                 + oldWidgetId);
                         host.deleteAppWidgetId(newWidgetIds[i]);
+                        launcherRestoreEventLogger.logSingleFavoritesItemRestoreFailed(
+                                ITEM_TYPE_APPWIDGET,
+                                RestoreError.WIDGET_REMOVED
+                        );
                     }
                 }
             }
         }
 
-        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app != null) {
-            app.getModel().forceReload();
-        }
+        logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
+        LauncherAppState.INSTANCE.executeIfCreated(app -> app.getModel().forceReload());
     }
 
     private static void logDatabaseWidgetInfo(ModelDbController controller) {
@@ -473,17 +557,16 @@
             StringBuilder builder = new StringBuilder();
             builder.append("[");
             for (int i = 0; i < widgetIdList.size(); i++) {
-                builder.append("[")
+                builder.append("[appWidgetId=")
                         .append(widgetIdList.get(i))
-                        .append(", ")
+                        .append(", restoreFlag=")
                         .append(widgetRestoreList.get(i))
-                        .append(", ")
+                        .append(", profileId=")
                         .append(widgetProfileIdList.get(i))
                         .append("]");
             }
             builder.append("]");
-            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
-                    + builder);
+            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: " + builder);
         } catch (Exception ex) {
             Log.e(TAG, "Getting widget ids from the database failed", ex);
         }
@@ -491,9 +574,8 @@
 
     protected static void maybeOverrideShortcuts(Context context, ModelDbController controller,
             SQLiteDatabase db, long currentUser) {
-        Map<String, LauncherActivityInfo> activityOverrides = ApiWrapper.getActivityOverrides(
-                context);
-
+        Map<String, LauncherActivityInfo> activityOverrides =
+                ApiWrapper.INSTANCE.get(context).getActivityOverrides();
         if (activityOverrides == null || activityOverrides.isEmpty()) {
             return;
         }
@@ -542,7 +624,7 @@
      */
     public static void logFavoritesTable(SQLiteDatabase database, @NonNull String logHeader,
             String where, String[] profileIds) {
-        try (Cursor itemsToDelete = database.query(
+        try (Cursor cursor = database.query(
                 /* table */ Favorites.TABLE_NAME,
                 /* columns */ DB_COLUMNS_TO_LOG,
                 /* selection */ where,
@@ -551,26 +633,53 @@
                 /* having */ null,
                 /* orderBy */ null
         )) {
-            if (itemsToDelete.moveToFirst()) {
-                String[] columnNames = itemsToDelete.getColumnNames();
+            if (cursor.moveToFirst()) {
+                String[] columnNames = cursor.getColumnNames();
                 StringBuilder stringBuilder = new StringBuilder(logHeader + "\n");
                 do {
                     for (String columnName : columnNames) {
                         stringBuilder.append(columnName)
                                 .append("=")
-                                .append(itemsToDelete.getString(
-                                        itemsToDelete.getColumnIndex(columnName)))
+                                .append(cursor.getString(
+                                        cursor.getColumnIndex(columnName)))
                                 .append(" ");
                     }
                     stringBuilder.append("\n");
-                } while (itemsToDelete.moveToNext());
+                } while (cursor.moveToNext());
                 FileLog.d(TAG, stringBuilder.toString());
             } else {
-                FileLog.d(TAG, "logFavoritesTable: No items found from query for"
+                FileLog.d(TAG, "logFavoritesTable: No items found from query for "
                         + "\"" + logHeader + "\"");
             }
         } catch (Exception e) {
             FileLog.e(TAG, "logFavoritesTable: Error reading from database", e);
         }
     }
+
+
+    /**
+     * Queries and reports the count of each itemType to be removed due to unrestored profiles.
+     * @param database The Launcher db to query from.
+     * @param where Query being used for to find unrestored profiles
+     * @param profileIds profile ids that were not restored
+     * @param restoreEventLogger Backup/Restore Logger to report metrics
+     */
+    private void reportUnrestoredProfiles(SQLiteDatabase database, String where,
+            String[] profileIds, LauncherRestoreEventLogger restoreEventLogger) {
+        final String query = "SELECT itemType, COUNT(*) AS count FROM favorites WHERE "
+                + where + " GROUP BY itemType";
+        try (Cursor cursor = database.rawQuery(query, profileIds)) {
+            if (cursor.moveToFirst()) {
+                do {
+                    restoreEventLogger.logFavoritesItemsRestoreFailed(
+                            cursor.getInt(cursor.getColumnIndexOrThrow(ITEM_TYPE)),
+                            cursor.getInt(cursor.getColumnIndexOrThrow("count")),
+                            RestoreError.PROFILE_NOT_RESTORED
+                    );
+                } while (cursor.moveToNext());
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "reportUnrestoredProfiles: Error reading from database", e);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
index 45174a7..43027da 100644
--- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
+++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt
@@ -23,10 +23,10 @@
 import com.android.launcher3.BubbleTextView
 import com.android.launcher3.allapps.BaseAllAppsAdapter
 import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.util.CancellableTask
 import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
 import com.android.launcher3.views.ActivityContext
-import java.util.concurrent.Future
 
 const val PREINFLATE_ICONS_ROW_COUNT = 4
 const val EXTRA_ICONS_COUNT = 2
@@ -38,9 +38,8 @@
  */
 class AllAppsRecyclerViewPool<T> : RecycledViewPool() {
 
-    private var future: Future<Void>? = null
-
     var hasWorkProfile = false
+    private var mCancellableTask: CancellableTask<List<ViewHolder>>? = null
 
     /**
      * Preinflate app icons. If all apps RV cannot be scrolled down, we don't need to preinflate.
@@ -63,21 +62,40 @@
                 override fun getLayoutManager(): RecyclerView.LayoutManager? = null
             }
 
-        // Inflate view holders on background thread, and added to view pool on main thread.
-        future?.cancel(true)
-        future =
-            VIEW_PREINFLATION_EXECUTOR.submit<Void> {
-                val viewHolders =
-                    Array(preInflateCount) {
-                        adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
+        mCancellableTask?.cancel()
+        var task: CancellableTask<List<ViewHolder>>? = null
+        task =
+            CancellableTask(
+                {
+                    val list: ArrayList<ViewHolder> = ArrayList()
+                    for (i in 0 until preInflateCount) {
+                        if (task?.canceled == true) {
+                            break
+                        }
+                        list.add(
+                            adapter.createViewHolder(activeRv, BaseAllAppsAdapter.VIEW_TYPE_ICON)
+                        )
                     }
-                MAIN_EXECUTOR.execute {
+                    list
+                },
+                MAIN_EXECUTOR,
+                { viewHolders ->
                     for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) {
                         putRecycledView(viewHolders[i])
                     }
                 }
-                null
-            }
+            )
+        mCancellableTask = task
+        VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask)
+    }
+
+    /**
+     * When clearing [RecycledViewPool], we should also abort pre-inflation tasks. This will make
+     * sure we don't inflate app icons after DeviceProfile has changed.
+     */
+    override fun clear() {
+        super.clear()
+        mCancellableTask?.cancel()
     }
 
     /**
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpec.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
index b0e1b27..65e0b32 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpec.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -59,7 +59,7 @@
     val cellSize: SizeSpec,
 ) : IResponsiveSpec {
     init {
-        check(isValid()) { "Invalid ResponsiveSpec found." }
+        check(isValid()) { "Invalid ResponsiveSpec found. $this" }
     }
 
     constructor(
@@ -106,7 +106,7 @@
         }
 
         if (!isValidRemainderSpace()) {
-            logError("The total Remainder Space used must be lower or equal to 100%.")
+            logError("The total Remainder Space used must be equal to 0 or 1.")
             return false
         }
 
@@ -131,11 +131,12 @@
     }
 
     private fun isValidRemainderSpace(): Boolean {
-        // TODO(b/313621277): This validation must be update do accept only 0 or 1 instead of <= 1f.
-        return startPadding.ofRemainderSpace +
-            endPadding.ofRemainderSpace +
-            gutter.ofRemainderSpace +
-            cellSize.ofRemainderSpace <= 1f
+        val remainderSpaceUsed =
+            startPadding.ofRemainderSpace +
+                endPadding.ofRemainderSpace +
+                gutter.ofRemainderSpace +
+                cellSize.ofRemainderSpace
+        return remainderSpaceUsed == 0f || remainderSpaceUsed == 1f
     }
 
     private fun isValidAvailableSpace(): Boolean {
@@ -254,8 +255,8 @@
 
         startPaddingPx = spec.startPadding.getRemainderSpaceValue(remainderSpace, startPaddingPx)
         endPaddingPx = spec.endPadding.getRemainderSpaceValue(remainderSpace, endPaddingPx)
-        gutterPx = spec.gutter.getRemainderSpaceValue(remainderSpace, gutterPx)
-        cellSizePx = spec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx)
+        gutterPx = spec.gutter.getRemainderSpaceValue(remainderSpace, gutterPx, gutters)
+        cellSizePx = spec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx, cells)
     }
 
     override fun hashCode(): Int {
diff --git a/src/com/android/launcher3/responsive/SizeSpec.kt b/src/com/android/launcher3/responsive/SizeSpec.kt
index d146898..41dcd5e 100644
--- a/src/com/android/launcher3/responsive/SizeSpec.kt
+++ b/src/com/android/launcher3/responsive/SizeSpec.kt
@@ -57,11 +57,16 @@
     /**
      * Calculates the [SizeSpec] value when remainder space value is defined. If no remainderSpace
      * is 0, returns a default value.
+     *
+     * @param remainderSpace The remainder space to be used for the calculation
+     * @param defaultValue The default value to be returned when no ofRemainderSpace is defined
+     * @param factor A number to divide the remainder space. The default value is 1. This property
+     *   is used to split equally the remainder space by the number of cells and gutters.
      */
-    fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int): Int {
+    fun getRemainderSpaceValue(remainderSpace: Int, defaultValue: Int, factor: Int = 1): Int {
         val remainderSpaceValue =
             if (ofRemainderSpace > 0) {
-                (ofRemainderSpace * remainderSpace).roundToInt()
+                (ofRemainderSpace * remainderSpace / factor).roundToInt()
             } else {
                 defaultValue
             }
diff --git a/src/com/android/launcher3/search/StringMatcherUtility.java b/src/com/android/launcher3/search/StringMatcherUtility.java
index 28fc4f0..7446314 100644
--- a/src/com/android/launcher3/search/StringMatcherUtility.java
+++ b/src/com/android/launcher3/search/StringMatcherUtility.java
@@ -18,6 +18,8 @@
 
 import android.text.TextUtils;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.util.IntArray;
 
 import java.text.Collator;
@@ -120,7 +122,11 @@
         /**
          * Returns true if {@param query} is a prefix of {@param target}
          */
-        public boolean matches(String query, String target) {
+        public boolean matches(@Nullable String query, @Nullable String target) {
+            // `mCollator.compare` requires non-null inputs, so return false earlier (not a match)
+            if (query == null || target == null) {
+                return false;
+            }
             switch (mCollator.compare(query, target)) {
                 case 0:
                     return true;
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 910b029..0299a23 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -200,11 +200,6 @@
     }
 
     @Override
-    public <T extends View> T getOverviewPanel() {
-        return null;
-    }
-
-    @Override
     public View getRootView() {
         return mDragLayer;
     }
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java
index 8d1d96b..79b25a4 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.secondarydisplay;
 
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -129,6 +131,10 @@
         dragView.show(mLastTouch.x, mLastTouch.y);
         mDistanceSinceScroll = 0;
 
+        if (!isItemPinnable()) {
+            MAIN_EXECUTOR.post(this:: cancelDrag);
+        }
+
         if (!mIsInPreDrag) {
             callOnDragStart();
         } else if (mOptions.preDragCondition != null) {
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 8cb15a5..52ce4e8 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -41,7 +41,6 @@
 import androidx.fragment.app.FragmentActivity;
 import androidx.fragment.app.FragmentManager;
 import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceFragmentCompat;
 import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback;
 import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback;
@@ -52,12 +51,8 @@
 import com.android.launcher3.BuildConfig;
 import com.android.launcher3.LauncherFiles;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.states.RotationHelper;
-import com.android.launcher3.uioverrides.flags.DeveloperOptionsUI;
 import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.SettingsCache;
 
 /**
@@ -120,7 +115,7 @@
     }
 
     private boolean startPreference(String fragment, Bundle args, String key) {
-        if (Utilities.ATLEAST_P && getSupportFragmentManager().isStateSaved()) {
+        if (getSupportFragmentManager().isStateSaved()) {
             // Sometimes onClick can come after onPause because of being posted on the handler.
             // Skip starting new preferences in that case.
             return false;
@@ -239,7 +234,7 @@
         protected boolean initPreference(Preference preference) {
             switch (preference.getKey()) {
                 case NOTIFICATION_DOTS_PREFERENCE_KEY:
-                    return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;
+                    return BuildConfig.NOTIFICATION_DOTS_ENABLED;
 
                 case ALLOW_ROTATION_PREFERENCE_KEY:
                     DisplayController.Info info =
@@ -257,12 +252,6 @@
                         preference.setOrder(0);
                     }
                     return mDeveloperOptionsEnabled;
-                case "pref_developer_flags":
-                    if (mDeveloperOptionsEnabled && preference instanceof PreferenceCategory pc) {
-                        Executors.MAIN_EXECUTOR.post(() -> new DeveloperOptionsUI(this, pc));
-                        return true;
-                    }
-                    return false;
             }
 
             return true;
diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
index 21efceb..015d54d 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutRequest.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.shortcuts;
 
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -47,7 +47,7 @@
             | ShortcutQuery.FLAG_MATCH_MANIFEST;
     public static final int PINNED = ShortcutQuery.FLAG_MATCH_PINNED;
 
-    private final ShortcutQuery mQuery = GO_DISABLE_WIDGETS ? null : new ShortcutQuery();
+    private final ShortcutQuery mQuery = !WIDGETS_ENABLED ? null : new ShortcutQuery();
 
     private final Context mContext;
     private final UserHandle mUserHandle;
@@ -74,7 +74,7 @@
      * @return A list of ShortcutInfo's associated with the given package.
      */
     public ShortcutRequest forPackage(String packageName, @Nullable List<String> shortcutIds) {
-        if (!GO_DISABLE_WIDGETS && packageName != null) {
+        if (WIDGETS_ENABLED && packageName != null) {
             mQuery.setPackage(packageName);
             mQuery.setShortcutIds(shortcutIds);
         }
@@ -82,7 +82,7 @@
     }
 
     public ShortcutRequest withContainer(@Nullable ComponentName activity) {
-        if (!GO_DISABLE_WIDGETS) {
+        if (WIDGETS_ENABLED) {
             if (activity == null) {
                 mFailed = true;
             } else {
@@ -93,7 +93,7 @@
     }
 
     public QueryResult query(int flags) {
-        if (GO_DISABLE_WIDGETS || mFailed) {
+        if (!WIDGETS_ENABLED || mFailed) {
             return QueryResult.DEFAULT;
         }
         mQuery.setQueryFlags(flags);
@@ -109,7 +109,7 @@
 
     public static class QueryResult extends ArrayList<ShortcutInfo> {
 
-        static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_WIDGETS);
+        static final QueryResult DEFAULT = new QueryResult(!WIDGETS_ENABLED);
 
         private final boolean mWasSuccess;
 
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 360ff7e..51bc339 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -19,6 +19,7 @@
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
 import static com.android.launcher3.anim.AnimatorPlaybackController.callListenerCommandRecursively;
+import static com.android.launcher3.states.StateAnimationConfig.HANDLE_STATE_APPLY;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS;
 
 import android.animation.Animator;
@@ -36,10 +37,12 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.states.StateAnimationConfig.AnimationPropertyFlags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.stream.Collectors;
 
 /**
  * Class to manage transitions between different states for a StatefulActivity based on different
@@ -48,6 +51,8 @@
 public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
 
     public static final String TAG = "StateManager";
+    // b/279059025
+    private static final boolean DEBUG = true;
 
     private final AnimationState mConfig = new AnimationState();
     private final Handler mUiHandler;
@@ -154,6 +159,13 @@
     /**
      * @see #goToState(STATE_TYPE, boolean, AnimatorListener)
      */
+    public void goToState(STATE_TYPE state, AnimatorListener listener) {
+        goToState(state, shouldAnimateStateChange(), listener);
+    }
+
+    /**
+     * @see #goToState(STATE_TYPE, boolean, AnimatorListener)
+     */
     public void goToState(STATE_TYPE state, boolean animated) {
         goToState(state, animated, 0, null);
     }
@@ -163,7 +175,7 @@
      *
      * @param animated false if the state should change immediately without any animation,
      *                true otherwise
-     * @paras onCompleteRunnable any action to perform at the end of the transition, of null.
+     * @param listener any action to perform at the end of the transition, or null.
      */
     public void goToState(STATE_TYPE state, boolean animated, AnimatorListener listener) {
         goToState(state, animated, 0, listener);
@@ -189,7 +201,7 @@
 
     public void reapplyState(boolean cancelCurrentAnimation) {
         boolean wasInAnimation = mConfig.currentAnimation != null;
-        if (cancelCurrentAnimation) {
+        if (cancelCurrentAnimation && (mConfig.animProps & HANDLE_STATE_APPLY) == 0) {
             // Animation canceling can trigger a cleanup routine, causing problems when we are in a
             // launcher state that relies on member variable data. So if we are in one of those
             // states, accelerate the current animation to its end point rather than canceling it
@@ -227,7 +239,18 @@
 
     private void goToState(
             STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "go to state " + state);
+        if (DEBUG) {
+            String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+            String truncatedTrace =
+                    Arrays.stream(stackTrace.split("\\n"))
+                            .limit(5)
+                            .skip(1) // Removes the line "java.lang.Exception: tracing state
+                            // transition"
+                            .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
+                            .collect(Collectors.joining("\n"));
+            Log.d(TAG, "goToState - fromState: " + mState + ", toState: " + state
+                    + ", partial trace:\n" + truncatedTrace);
+        }
 
         animated &= areAnimatorsEnabled();
         if (mActivity.isInState(state)) {
@@ -237,7 +260,7 @@
                     listener.onAnimationEnd(null);
                 }
                 return;
-            } else if ((!mConfig.userControlled && animated && mConfig.targetState == state)
+            } else if ((!mConfig.isUserControlled() && animated && mConfig.targetState == state)
                     || mState.shouldPreserveDataStateOnReapply()) {
                 // We are running the same animation as requested, and/or target state should not be
                 // reset -- allow the current animation to complete instead of canceling it.
@@ -312,6 +335,20 @@
      */
     public AnimatorSet createAtomicAnimation(
             STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
+        if (DEBUG) {
+            String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+            String truncatedTrace =
+                    Arrays.stream(stackTrace.split("\\n"))
+                            .limit(5)
+                            .skip(1) // Removes the line "java.lang.Exception: tracing state
+                            // transition"
+                            .filter(traceLine -> !traceLine.contains(
+                                    "StateManager.createAtomicAnimation"))
+                            .collect(Collectors.joining("\n"));
+            Log.d(TAG, "createAtomicAnimation - fromState: " + fromState + ", toState: " + toState
+                    + ", partial trace:\n" + truncatedTrace);
+        }
+
         PendingAnimation builder = new PendingAnimation(config.duration);
         prepareForAtomicAnimation(fromState, toState, config);
 
@@ -343,7 +380,7 @@
 
     public AnimatorPlaybackController createAnimationToNewWorkspace(STATE_TYPE state,
             StateAnimationConfig config) {
-        config.userControlled = true;
+        config.animProps |= StateAnimationConfig.USER_CONTROLLED;
         cancelAnimation();
         config.copyTo(mConfig);
         mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
@@ -383,8 +420,9 @@
         mState = state;
         mActivity.onStateSetStart(mState);
 
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying listeners for state transition start"
-                + " to state: " + state.toString());
+        if (DEBUG) {
+            Log.d(TAG, "onStateTransitionStart - state: " + state);
+        }
         for (int i = mListeners.size() - 1; i >= 0; i--) {
             mListeners.get(i).onStateTransitionStart(state);
         }
@@ -402,8 +440,9 @@
             setRestState(null);
         }
 
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying " + mListeners.size() + " listeners "
-                + "for end transition for state: " + state.toString());
+        if (DEBUG) {
+            Log.d(TAG, "onStateTransitionEnd - state: " + state);
+        }
         for (int i = mListeners.size() - 1; i >= 0; i--) {
             mListeners.get(i).onStateTransitionComplete(state);
         }
@@ -418,7 +457,7 @@
     }
 
     public void moveToRestState(boolean isAnimated) {
-        if (mConfig.currentAnimation != null && mConfig.userControlled) {
+        if (mConfig.currentAnimation != null && mConfig.isUserControlled()) {
             // The user is doing something. Lets not mess it up
             return;
         }
@@ -441,7 +480,9 @@
      * Cancels the current animation.
      */
     public void cancelAnimation() {
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "current animation cancelled");
+        if (DEBUG && mConfig.currentAnimation != null) {
+            Log.d(TAG, "cancelAnimation - with ongoing animation");
+        }
         mConfig.reset();
         // It could happen that a new animation is set as a result of an endListener on the
         // existing animation.
@@ -450,10 +491,18 @@
         }
     }
 
+    /**
+     * Sets the provided controller as the current user controlled state animation
+     */
     public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) {
+        setCurrentAnimation(controller, StateAnimationConfig.USER_CONTROLLED);
+    }
+
+    public void setCurrentAnimation(AnimatorPlaybackController controller,
+            @AnimationPropertyFlags int animationProps) {
         clearCurrentAnimation();
         setCurrentAnimation(controller.getTarget());
-        mConfig.userControlled = true;
+        mConfig.animProps = animationProps;
         mConfig.playbackController = controller;
     }
 
@@ -465,7 +514,6 @@
      * @param toState The state we are animating towards.
      */
     public void setCurrentAnimation(AnimatorSet anim, STATE_TYPE toState) {
-        Log.d(TestProtocol.OVERVIEW_OVER_HOME, "setting animation to " + toState.toString());
         cancelAnimation();
         setCurrentAnimation(anim);
         anim.addListener(createStateAnimationListener(toState));
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 520f33c..30ba703 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -126,16 +126,8 @@
 
     @Override
     public void reapplyUi() {
-        reapplyUi(true /* cancelCurrentAnimation */);
-    }
-
-    /**
-     * Re-applies if any state transition is not running, optionally cancelling
-     * the transition if requested.
-     */
-    public void reapplyUi(boolean cancelCurrentAnimation) {
         getRootView().dispatchInsets();
-        getStateManager().reapplyState(cancelCurrentAnimation);
+        getStateManager().reapplyState(true /* cancelCurrentAnimation */);
     }
 
     @Override
diff --git a/src/com/android/launcher3/states/EditModeState.kt b/src/com/android/launcher3/states/EditModeState.kt
index aafaaa0..6ff47ae 100644
--- a/src/com/android/launcher3/states/EditModeState.kt
+++ b/src/com/android/launcher3/states/EditModeState.kt
@@ -16,6 +16,7 @@
 package com.android.launcher3.states
 
 import android.content.Context
+import com.android.launcher3.Flags.enableScalingRevealHomeAnimation
 import com.android.launcher3.Launcher
 import com.android.launcher3.LauncherState
 import com.android.launcher3.logging.StatsLogManager
@@ -25,6 +26,8 @@
 class EditModeState(id: Int) : LauncherState(id, StatsLogManager.LAUNCHER_STATE_HOME, STATE_FLAGS) {
 
     companion object {
+        const val DEPTH_15_PERCENT = 0.15f
+
         private val STATE_FLAGS =
             (FLAG_MULTI_PAGE or
                 FLAG_WORKSPACE_INACCESSIBLE or
@@ -40,7 +43,11 @@
     }
 
     override fun <T> getDepthUnchecked(context: T): Float where T : Context?, T : ActivityContext? {
-        return 0.5f
+        if (enableScalingRevealHomeAnimation()) {
+            return DEPTH_15_PERCENT
+        } else {
+            return 0.5f
+        }
     }
 
     override fun getWorkspaceScaleAndTranslation(launcher: Launcher): ScaleAndTranslation {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 4cfced8..bf2fb30 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.states;
 
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 
 import android.content.Context;
@@ -34,6 +35,8 @@
     private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
             | FLAG_HAS_SYS_UI_SCRIM;
 
+    public static final float DEPTH_5_PERCENT = 0.05f;
+
     public HintState(int id) {
         this(id, LAUNCHER_STATE_HOME);
     }
@@ -49,7 +52,11 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        return 0.15f;
+        if (enableScalingRevealHomeAnimation()) {
+            return DEPTH_5_PERCENT;
+        } else {
+            return 0.15f;
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 6950fb5..fdb37f0 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -35,6 +35,7 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.BaseActivity;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.util.DisplayController;
 
@@ -42,6 +43,7 @@
  * Utility class to manage launcher rotation
  */
 public class RotationHelper implements OnSharedPreferenceChangeListener,
+        DeviceProfile.OnDeviceProfileChangeListener,
         DisplayController.DisplayInfoChangeListener {
 
     public static final String ALLOW_ROTATION_PREFERENCE_KEY = "pref_allowRotation";
@@ -119,10 +121,24 @@
         }
     }
 
+    /**
+     * Listening to both onDisplayInfoChanged and onDeviceProfileChanged to reduce delay. While
+     * onDeviceProfileChanged is triggered earlier, it only receives callback when Launcher is in
+     * the foreground. When in the background, we can still rely on onDisplayInfoChanged to update,
+     * assuming that the delay is tolerable since it takes time to change to foreground.
+     */
     @Override
     public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
+        onIgnoreAutoRotateChanged(info.isTablet(info.realBounds));
+    }
+
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        onIgnoreAutoRotateChanged(dp.isTablet);
+    }
+
+    private void onIgnoreAutoRotateChanged(boolean ignoreAutoRotateSettings) {
         if (mDestroyed) return;
-        boolean ignoreAutoRotateSettings = info.isTablet(info.realBounds);
         if (mIgnoreAutoRotateSettings != ignoreAutoRotateSettings) {
             setIgnoreAutoRotateSettings(ignoreAutoRotateSettings);
             notifyChange();
@@ -161,12 +177,14 @@
         DisplayController.Info info = displayController.getInfo();
         setIgnoreAutoRotateSettings(info.isTablet(info.realBounds));
         displayController.addChangeListener(this);
+        mActivity.addOnDeviceProfileChangeListener(this);
         notifyChange();
     }
 
     public void destroy() {
         if (mDestroyed) return;
         mDestroyed = true;
+        mActivity.removeOnDeviceProfileChangeListener(this);
         DisplayController.INSTANCE.get(mActivity).removeChangeListener(this);
         LauncherPrefs.get(mActivity).removeListener(this, ALLOW_ROTATION);
     }
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 3286afb..2e57ed8 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.states;
 
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 
 import android.content.Context;
@@ -33,6 +34,8 @@
             | FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
             | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_WORKSPACE_HAS_BACKGROUNDS;
 
+    public static final float DEPTH_15_PERCENT = 0.15f;
+
     public SpringLoadedState(int id) {
         super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
     }
@@ -62,7 +65,11 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        return 0.5f;
+        if (enableScalingRevealHomeAnimation()) {
+            return DEPTH_15_PERCENT;
+        } else {
+            return 0.5f;
+        }
     }
 
     @Override
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 0d9e010..0ca5afd 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -40,8 +40,19 @@
     public static final int SKIP_DEPTH_CONTROLLER = 1 << 2;
     public static final int SKIP_SCRIM = 1 << 3;
 
+    @IntDef(flag = true, value = {
+            USER_CONTROLLED,
+            HANDLE_STATE_APPLY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AnimationPropertyFlags {}
+    // Indicates that the animation is controlled by the user
+    public static final int USER_CONTROLLED = 1 << 0;
+    // Indicates that he animation can survive state UI resets due to inset or config changes
+    public static final int HANDLE_STATE_APPLY = 1 << 1;
+
     public long duration;
-    public boolean userControlled;
+    public @AnimationPropertyFlags int animProps = 0;
     public @AnimationFlags int animFlags = 0;
 
 
@@ -105,12 +116,16 @@
     public void copyTo(StateAnimationConfig target) {
         target.duration = duration;
         target.animFlags = animFlags;
-        target.userControlled = userControlled;
+        target.animProps = animProps;
         for (int i = 0; i < ANIM_TYPES_COUNT; i++) {
             target.mInterpolators[i] = mInterpolators[i];
         }
     }
 
+    public boolean isUserControlled() {
+        return (animProps & USER_CONTROLLED) != 0;
+    }
+
     /**
      * Returns the interpolator set for animId or fallback if nothing is set
      *
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 2c834bd..db2a6e0 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -15,52 +15,70 @@
  */
 package com.android.launcher3.testing;
 
-import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
 import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
+import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
+import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
-import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.Application;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.Build;
+import android.os.Binder;
 import android.os.Bundle;
+import android.system.Os;
 import android.view.WindowInsets;
 
+import androidx.annotation.Keep;
 import androidx.annotation.Nullable;
 import androidx.core.view.WindowInsetsCompat;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.icons.ClockDrawableWrapper;
 import com.android.launcher3.testing.shared.HotseatCellCenterRequest;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest;
+import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
 /**
  * Class to handle requests from tests
  */
-@TargetApi(Build.VERSION_CODES.Q)
 public class TestInformationHandler implements ResourceBasedOverride {
 
     public static TestInformationHandler newInstance(Context context) {
@@ -68,15 +86,29 @@
                 context, R.string.test_information_handler_class);
     }
 
+    private static Collection<String> sEvents;
+    private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
+    private static final Set<Activity> sActivities =
+            Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
+    private static int sActivitiesCreatedCount = 0;
+
     protected Context mContext;
     protected DeviceProfile mDeviceProfile;
-    protected LauncherAppState mLauncherAppState;
 
     public void init(Context context) {
         mContext = context;
-        mDeviceProfile = InvariantDeviceProfile.INSTANCE.
-                get(context).getDeviceProfile(context);
-        mLauncherAppState = LauncherAppState.getInstanceNoCreate();
+        mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context);
+        if (sActivityLifecycleCallbacks == null) {
+            sActivityLifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
+                @Override
+                public void onActivityCreated(Activity activity, Bundle bundle) {
+                    sActivities.add(activity);
+                    ++sActivitiesCreatedCount;
+                }
+            };
+            ((Application) context.getApplicationContext())
+                    .registerActivityLifecycleCallbacks(sActivityLifecycleCallbacks);
+        }
     }
 
     /**
@@ -153,11 +185,19 @@
                 }, this::getCurrentActivity);
             }
 
-            case TestProtocol.REQUEST_IME_INSETS: {
+            case TestProtocol.REQUEST_CELL_LAYOUT_BOARDER_HEIGHT: {
+                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        mDeviceProfile.cellLayoutBorderSpacePx.y);
+                return response;
+            }
+
+            case TestProtocol.REQUEST_SYSTEM_GESTURE_REGION: {
                 return getUIProperty(Bundle::putParcelable, activity -> {
                     WindowInsetsCompat insets = WindowInsetsCompat.toWindowInsetsCompat(
                             activity.getWindow().getDecorView().getRootWindowInsets());
-                    return insets.getInsets(WindowInsetsCompat.Type.ime()).toPlatformInsets();
+                    return insets.getInsets(WindowInsetsCompat.Type.ime()
+                            | WindowInsetsCompat.Type.systemGestures())
+                            .toPlatformInsets();
                 }, this::getCurrentActivity);
             }
 
@@ -174,6 +214,14 @@
             case TestProtocol.REQUEST_IS_TABLET:
                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, mDeviceProfile.isTablet);
                 return response;
+            case TestProtocol.REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED:
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        mDeviceProfile.isPredictiveBackSwipe);
+                return response;
+            case TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION:
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        ENABLE_TASKBAR_NAVBAR_UNIFICATION);
+                return response;
 
             case TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS:
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
@@ -203,6 +251,11 @@
                 return response;
             }
 
+            case TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE:
+                response.putBoolean(TEST_INFO_RESPONSE_FIELD, enableSplitContextually()
+                        && Launcher.ACTIVITY_TRACKER.getCreatedActivity().isSplitSelectionActive());
+                return response;
+
             case TestProtocol.REQUEST_ENABLE_ROTATION:
                 MAIN_EXECUTOR.submit(() ->
                         Launcher.ACTIVITY_TRACKER.getCreatedActivity().getRotationHelper()
@@ -282,6 +335,132 @@
                 return response;
             }
 
+            case TestProtocol.REQUEST_FLAG_ENABLE_APP_PAIRS: {
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, enableAppPairs());
+                return response;
+            }
+
+            case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
+                return getLauncherUIProperty(Bundle::putInt,
+                        l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
+            }
+
+            case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
+                TestProtocol.sDebugTracing = true;
+                ClockDrawableWrapper.sRunningInTest = true;
+                return response;
+
+            case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
+                TestProtocol.sDebugTracing = false;
+                ClockDrawableWrapper.sRunningInTest = false;
+                return response;
+
+            case TestProtocol.REQUEST_PID: {
+                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
+                return response;
+            }
+
+            case TestProtocol.REQUEST_FORCE_GC: {
+                runGcAndFinalizersSync();
+                return response;
+            }
+
+            case TestProtocol.REQUEST_START_EVENT_LOGGING: {
+                sEvents = new ArrayList<>();
+                TestLogging.setEventConsumer(
+                        (sequence, event) -> {
+                            final Collection<String> events = sEvents;
+                            if (events != null) {
+                                synchronized (events) {
+                                    events.add(sequence + '/' + event);
+                                }
+                            }
+                        });
+                return response;
+            }
+
+            case TestProtocol.REQUEST_STOP_EVENT_LOGGING: {
+                TestLogging.setEventConsumer(null);
+                sEvents = null;
+                return response;
+            }
+
+            case TestProtocol.REQUEST_GET_TEST_EVENTS: {
+                if (sEvents == null) {
+                    // sEvents can be null if Launcher died and restarted after
+                    // REQUEST_START_EVENT_LOGGING.
+                    return response;
+                }
+
+                synchronized (sEvents) {
+                    response.putStringArrayList(
+                            TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
+                }
+                return response;
+            }
+
+            case TestProtocol.REQUEST_REINITIALIZE_DATA: {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    MODEL_EXECUTOR.execute(() -> {
+                        LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
+                        model.getModelDbController().createEmptyDB();
+                        MAIN_EXECUTOR.execute(model::forceReload);
+                    });
+                    return response;
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+
+            case TestProtocol.REQUEST_CLEAR_DATA: {
+                final long identity = Binder.clearCallingIdentity();
+                try {
+                    MODEL_EXECUTOR.execute(() -> {
+                        LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
+                        model.getModelDbController().createEmptyDB();
+                        model.getModelDbController().clearEmptyDbFlag();
+                        MAIN_EXECUTOR.execute(model::forceReload);
+                    });
+                    return response;
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
+                }
+            }
+
+            case TestProtocol.REQUEST_HOTSEAT_ICON_NAMES: {
+                return getLauncherUIProperty(Bundle::putStringArrayList, l -> {
+                    ShortcutAndWidgetContainer hotseatIconsContainer =
+                            l.getHotseat().getShortcutsAndWidgets();
+                    ArrayList<String> hotseatIconNames = new ArrayList<>();
+
+                    for (int i = 0; i < hotseatIconsContainer.getChildCount(); i++) {
+                        // Use unchecked cast to catch changes in hotseat layout
+                        BubbleTextView icon = (BubbleTextView) hotseatIconsContainer.getChildAt(i);
+                        hotseatIconNames.add((String) icon.getText());
+                    }
+
+                    return hotseatIconNames;
+                });
+            }
+
+            case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
+                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
+                return response;
+            }
+
+            case TestProtocol.REQUEST_GET_ACTIVITIES: {
+                response.putStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        sActivities.stream().map(
+                                        a -> a.getClass().getSimpleName() + " ("
+                                                + (a.isDestroyed() ? "destroyed" : "current") + ")")
+                                .toArray(String[]::new));
+                return response;
+            }
+
+            case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED:
+                return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new);
+
             default:
                 return null;
         }
@@ -330,6 +509,7 @@
                 return null;
             }
             T value = provider.apply(target);
+
             Bundle response = new Bundle();
             bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value);
             return response;
@@ -359,4 +539,38 @@
          */
         void set(Bundle b, String key, T value);
     }
+
+
+    private static void runGcAndFinalizersSync() {
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+
+        final CountDownLatch fence = new CountDownLatch(1);
+        createFinalizationObserver(fence);
+        try {
+            do {
+                Runtime.getRuntime().gc();
+                Runtime.getRuntime().runFinalization();
+            } while (!fence.await(100, TimeUnit.MILLISECONDS));
+        } catch (InterruptedException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    // Create the observer in the scope of a method to minimize the chance that
+    // it remains live in a DEX/machine register at the point of the fence guard.
+    // This must be kept to avoid R8 inlining it.
+    @Keep
+    private static void createFinalizationObserver(CountDownLatch fence) {
+        new Object() {
+            @Override
+            protected void finalize() throws Throwable {
+                try {
+                    fence.countDown();
+                } finally {
+                    super.finalize();
+                }
+            }
+        };
+    }
 }
diff --git a/src/com/android/launcher3/testing/TestLogging.java b/src/com/android/launcher3/testing/TestLogging.java
index 60d0e95..459fa07 100644
--- a/src/com/android/launcher3/testing/TestLogging.java
+++ b/src/com/android/launcher3/testing/TestLogging.java
@@ -62,7 +62,14 @@
 
     public static void recordKeyEvent(String sequence, String message, KeyEvent event) {
         if (Utilities.isRunningInTestHarness()) {
-            recordEventSlow(sequence, message + ": " + event, true);
+            // This removes expecting ACTION_DOWN key event in the test. ACTION_UP is
+            // always preceded by ACTION_DOWN.
+            // Sometimes test doesn't receive ACTION_DOWN key event and we will assume that
+            // Launcher relies only on ACTION_UP.
+            // However in the test we will send both ACTION_DOWN and ACTION_UP key events.
+            // But stop reporting to tapl if action is down.
+            boolean reportToTapl = event.getAction() != KeyEvent.ACTION_DOWN;
+            recordEventSlow(sequence, message + ": " + event, reportToTapl);
             registerEventNotFromTest(event);
         }
     }
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 9aed4eb..50f98f2 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -57,7 +57,7 @@
     protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
 
     protected final AnimatorListener mClearStateOnCancelListener =
-            newCancelListener(this::clearState);
+            newCancelListener(this::clearState, /* isSingleUse = */ false);
     private final FlingBlockCheck mFlingBlockCheck = new FlingBlockCheck();
 
     protected int mStartContainerType;
diff --git a/src/com/android/launcher3/touch/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java
index 8b9bc19..fe4a83b 100644
--- a/src/com/android/launcher3/touch/AllAppsSwipeController.java
+++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java
@@ -192,7 +192,7 @@
     protected StateAnimationConfig getConfigForStates(LauncherState fromState,
             LauncherState toState) {
         StateAnimationConfig config = super.getConfigForStates(fromState, toState);
-        config.userControlled = true;
+        config.animProps |= StateAnimationConfig.USER_CONTROLLED;
         if (fromState == NORMAL && toState == ALL_APPS) {
             applyNormalToAllAppsAnimConfig(mLauncher, config);
         } else if (fromState == ALL_APPS && toState == NORMAL) {
@@ -209,13 +209,13 @@
             config.setInterpolator(ANIM_SCRIM_FADE,
                     Interpolators.reverse(ALL_APPS_SCRIM_RESPONDER));
             config.setInterpolator(ANIM_ALL_APPS_FADE, FINAL_FRAME);
-            if (!config.userControlled) {
+            if (!config.isUserControlled()) {
                 config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
             }
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
             config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
         } else {
-            if (config.userControlled) {
+            if (config.isUserControlled()) {
                 config.setInterpolator(ANIM_DEPTH, Interpolators.reverse(BLUR_MANUAL));
                 config.setInterpolator(ANIM_WORKSPACE_FADE,
                         Interpolators.reverse(WORKSPACE_FADE_MANUAL));
@@ -250,29 +250,32 @@
         if (launcher.getDeviceProfile().isTablet) {
             config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
             config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
-            if (!config.userControlled) {
+            if (!config.isUserControlled()) {
                 config.setInterpolator(ANIM_VERTICAL_PROGRESS, EMPHASIZED);
             }
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DECELERATED_EASE);
             config.setInterpolator(ANIM_DEPTH, DECELERATED_EASE);
         } else {
-            config.setInterpolator(ANIM_DEPTH, config.userControlled ? BLUR_MANUAL : BLUR_ATOMIC);
+            config.setInterpolator(ANIM_DEPTH,
+                    config.isUserControlled() ? BLUR_MANUAL : BLUR_ATOMIC);
             config.setInterpolator(ANIM_WORKSPACE_FADE,
-                    config.userControlled ? WORKSPACE_FADE_MANUAL : WORKSPACE_FADE_ATOMIC);
+                    config.isUserControlled() ? WORKSPACE_FADE_MANUAL : WORKSPACE_FADE_ATOMIC);
             config.setInterpolator(ANIM_WORKSPACE_SCALE,
-                    config.userControlled ? WORKSPACE_SCALE_MANUAL : WORKSPACE_SCALE_ATOMIC);
+                    config.isUserControlled() ? WORKSPACE_SCALE_MANUAL : WORKSPACE_SCALE_ATOMIC);
             config.setInterpolator(ANIM_HOTSEAT_FADE,
-                    config.userControlled ? HOTSEAT_FADE_MANUAL : HOTSEAT_FADE_ATOMIC);
+                    config.isUserControlled() ? HOTSEAT_FADE_MANUAL : HOTSEAT_FADE_ATOMIC);
             config.setInterpolator(ANIM_HOTSEAT_SCALE,
-                    config.userControlled ? HOTSEAT_SCALE_MANUAL : HOTSEAT_SCALE_ATOMIC);
+                    config.isUserControlled() ? HOTSEAT_SCALE_MANUAL : HOTSEAT_SCALE_ATOMIC);
             config.setInterpolator(ANIM_HOTSEAT_TRANSLATE,
-                    config.userControlled ? HOTSEAT_TRANSLATE_MANUAL : HOTSEAT_TRANSLATE_ATOMIC);
+                    config.isUserControlled()
+                            ? HOTSEAT_TRANSLATE_MANUAL
+                            : HOTSEAT_TRANSLATE_ATOMIC);
             config.setInterpolator(ANIM_SCRIM_FADE,
-                    config.userControlled ? SCRIM_FADE_MANUAL : SCRIM_FADE_ATOMIC);
+                    config.isUserControlled() ? SCRIM_FADE_MANUAL : SCRIM_FADE_ATOMIC);
             config.setInterpolator(ANIM_ALL_APPS_FADE,
-                    config.userControlled ? ALL_APPS_FADE_MANUAL : ALL_APPS_FADE_ATOMIC);
+                    config.isUserControlled() ? ALL_APPS_FADE_MANUAL : ALL_APPS_FADE_ATOMIC);
             config.setInterpolator(ANIM_VERTICAL_PROGRESS,
-                    config.userControlled
+                    config.isUserControlled()
                             ? ALL_APPS_VERTICAL_PROGRESS_MANUAL
                             : ALL_APPS_VERTICAL_PROGRESS_ATOMIC);
         }
@@ -285,7 +288,7 @@
      */
     public static void applyOverviewToAllAppsAnimConfig(
             DeviceProfile deviceProfile, StateAnimationConfig config, float threshold) {
-        config.userControlled = true;
+        config.animProps |= StateAnimationConfig.USER_CONTROLLED;
         config.animFlags = SKIP_OVERVIEW;
         if (deviceProfile.isTablet) {
             config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
diff --git a/src/com/android/launcher3/touch/DefaultPagedViewHandler.java b/src/com/android/launcher3/touch/DefaultPagedViewHandler.java
new file mode 100644
index 0000000..272ed10
--- /dev/null
+++ b/src/com/android/launcher3/touch/DefaultPagedViewHandler.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.touch;
+
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import com.android.launcher3.Utilities;
+
+public class DefaultPagedViewHandler implements PagedOrientationHandler {
+    @Override
+    public int getPrimaryValue(int x, int y) {
+        return x;
+    }
+
+    @Override
+    public int getSecondaryValue(int x, int y) {
+        return y;
+    }
+
+    @Override
+    public float getPrimaryValue(float x, float y) {
+        return x;
+    }
+
+    @Override
+    public float getSecondaryValue(float x, float y) {
+        return y;
+    }
+
+    @Override
+    public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
+        action.call(target, param, 0);
+    }
+
+    @Override
+    public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
+        action.call(target, param, 0);
+    }
+
+    @Override
+    public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
+        return event.getX(pointerIndex);
+    }
+
+    @Override
+    public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
+        return velocityTracker.getXVelocity(pointerId);
+    }
+
+    @Override
+    public int getMeasuredSize(View view) {
+        return view.getMeasuredWidth();
+    }
+
+    @Override
+    public int getPrimaryScroll(View view) {
+        return view.getScrollX();
+    }
+
+    @Override
+    public float getPrimaryScale(View view) {
+        return view.getScaleX();
+    }
+
+    @Override
+    public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
+        event.setMaxScrollX(maxScroll);
+    }
+
+    @Override
+    public boolean getRecentsRtlSetting(Resources resources) {
+        return !Utilities.isRtl(resources);
+    }
+
+    @Override
+    public int getChildStart(View view) {
+        return view.getLeft();
+    }
+
+    @Override
+    public int getCenterForPage(View view, Rect insets) {
+        return (view.getPaddingTop() + view.getMeasuredHeight() + insets.top
+            - insets.bottom - view.getPaddingBottom()) / 2;
+    }
+
+    @Override
+    public int getScrollOffsetStart(View view, Rect insets) {
+        return insets.left + view.getPaddingLeft();
+    }
+
+    @Override
+    public int getScrollOffsetEnd(View view, Rect insets) {
+        return view.getWidth() - view.getPaddingRight() - insets.right;
+    }
+
+    @Override
+    public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
+            boolean layoutChild) {
+        final int childWidth = child.getMeasuredWidth();
+        final int childRight = childStart + childWidth;
+        final int childHeight = child.getMeasuredHeight();
+        final int childTop = pageCenter - childHeight / 2;
+        if (layoutChild) {
+            child.layout(childStart, childTop, childRight, childTop + childHeight);
+        }
+        return new ChildBounds(childWidth, childHeight, childRight, childTop);
+    }
+
+}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index a9c2a2e..0ed6ea0 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
 import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
@@ -31,6 +32,7 @@
 import android.content.Intent;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller.SessionInfo;
+import android.os.Process;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -38,6 +40,9 @@
 import android.widget.Toast;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Flags;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
@@ -49,6 +54,7 @@
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -58,8 +64,8 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.views.FloatingIconView;
 import com.android.launcher3.views.Snackbar;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -97,11 +103,9 @@
         if (tag instanceof WorkspaceItemInfo) {
             onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
         } else if (tag instanceof FolderInfo) {
-            if (v instanceof FolderIcon) {
-                onClickFolderIcon(v);
-            } else if (v instanceof AppPairIcon) {
-                onClickAppPairIcon(v);
-            }
+            onClickFolderIcon(v);
+        } else if (tag instanceof AppPairInfo) {
+            onClickAppPairIcon(v);
         } else if (tag instanceof AppInfo) {
             startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
         } else if (tag instanceof LauncherAppWidgetInfo) {
@@ -145,8 +149,40 @@
      */
     private static void onClickAppPairIcon(View v) {
         Launcher launcher = Launcher.getLauncher(v.getContext());
-        AppPairIcon appPairIcon = (AppPairIcon) v;
-        launcher.launchAppPair(appPairIcon);
+        AppPairIcon icon = (AppPairIcon) v;
+        AppPairInfo info = icon.getInfo();
+        boolean isApp1Launchable = info.isLaunchable(launcher).getFirst(),
+                isApp2Launchable = info.isLaunchable(launcher).getSecond();
+        if (!isApp1Launchable || !isApp2Launchable) {
+            // App pair is unlaunchable due to screen size.
+            boolean isFoldable = InvariantDeviceProfile.INSTANCE.get(launcher)
+                    .supportedProfiles.stream().anyMatch(dp -> dp.isTwoPanels);
+            Toast.makeText(launcher, isFoldable
+                            ? R.string.app_pair_needs_unfold
+                            : R.string.app_pair_unlaunchable_at_screen_size,
+                    Toast.LENGTH_SHORT).show();
+            return;
+        } else if (info.isDisabled()) {
+            // App pair is disabled for another reason.
+            WorkspaceItemInfo app1 = info.getFirstApp();
+            WorkspaceItemInfo app2 = info.getSecondApp();
+            // Show the user why the app pair is disabled.
+            if (app1.isDisabled() && app2.isDisabled()) {
+                // Both apps are disabled, show generic "app pair is not available" toast.
+                Toast.makeText(launcher, R.string.app_pair_not_available, Toast.LENGTH_SHORT)
+                        .show();
+                return;
+            } else if ((app1.isDisabled() && handleDisabledItemClicked(app1, launcher))
+                    || (app2.isDisabled() && handleDisabledItemClicked(app2, launcher))) {
+                // Only one is disabled, and handleDisabledItemClicked() showed a specific toast
+                // explaining why, so we are done.
+                return;
+            }
+        }
+
+        // Either the app pair is not disabled, or it is a disabled state that can be handled by
+        // framework directly (e.g. one app is paused), so go ahead and launch.
+        launcher.launchAppPair(icon);
     }
 
     /**
@@ -187,16 +223,12 @@
             boolean downloadStarted) {
         ItemInfo item = (ItemInfo) v.getTag();
         CompletableFuture<SessionInfo> siFuture;
-        if (Utilities.ATLEAST_Q) {
-            siFuture = CompletableFuture.supplyAsync(() ->
-                    InstallSessionHelper.INSTANCE.get(launcher)
-                            .getActiveSessionInfo(item.user, packageName),
-                    UI_HELPER_EXECUTOR);
-        } else {
-            siFuture = CompletableFuture.completedFuture(null);
-        }
+        siFuture = CompletableFuture.supplyAsync(() ->
+                        InstallSessionHelper.INSTANCE.get(launcher)
+                                .getActiveSessionInfo(item.user, packageName),
+                UI_HELPER_EXECUTOR);
         Consumer<SessionInfo> marketLaunchAction = sessionInfo -> {
-            if (sessionInfo != null && Utilities.ATLEAST_Q) {
+            if (sessionInfo != null) {
                 LauncherApps launcherApps = launcher.getSystemService(LauncherApps.class);
                 try {
                     launcherApps.startPackageInstallerSessionDetailsActivity(sessionInfo, null,
@@ -207,7 +239,8 @@
                 }
             }
             // Fallback to using custom market intent.
-            Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
+            Intent intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent(
+                    packageName, Process.myUserHandle());
             launcher.startActivitySafely(v, intent, item);
         };
 
@@ -317,7 +350,8 @@
         }
 
         // Check for abandoned promise
-        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
+        if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()
+                && (!Flags.enableSupportForArchiving() || !shortcut.isArchived())) {
             String packageName = shortcut.getIntent().getComponent() != null
                     ? shortcut.getIntent().getComponent().getPackageName()
                     : shortcut.getIntent().getPackage();
@@ -339,15 +373,21 @@
     private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
         TestLogging.recordEvent(
                 TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
-        Intent intent;
-        if (item instanceof ItemInfoWithIcon
-                && (((ItemInfoWithIcon) item).runtimeStatusFlags
-                & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
-            ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
-            intent = new PackageManagerHelper(launcher)
-                    .getMarketIntent(appInfo.getTargetComponent().getPackageName());
-        } else {
-            intent = item.getIntent();
+        Intent intent = item.getIntent();
+        if (item instanceof ItemInfoWithIcon itemInfoWithIcon) {
+            if ((itemInfoWithIcon.runtimeStatusFlags
+                    & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+                intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent(
+                        itemInfoWithIcon.getTargetComponent().getPackageName(),
+                        Process.myUserHandle());
+            } else if (itemInfoWithIcon.itemType
+                    == LauncherSettings.Favorites.ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON) {
+                intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent(
+                        BuildConfig.APPLICATION_ID,
+                        launcher.getAppsView().getPrivateProfileManager().getProfileUser());
+                launcher.getStatsLogManager().logger().log(
+                        LAUNCHER_PRIVATE_SPACE_INSTALL_APP_BUTTON_TAP);
+            }
         }
         if (intent == null) {
             throw new IllegalArgumentException("Input must have a valid intent");
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 9e7d4dc..89057a2 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.PrivateSpaceInstallAppButtonInfo;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.views.BubbleTextHolder;
@@ -150,7 +151,10 @@
         if (launcher.getWorkspace().isSwitchingState()) return false;
 
         StatsLogger logger = launcher.getStatsLogManager().logger();
-        if (v.getTag() instanceof ItemInfo) {
+        if (v.getTag() instanceof ItemInfo itemInfo) {
+            if (itemInfo instanceof PrivateSpaceInstallAppButtonInfo) {
+                return false;
+            }
             logger.withItemInfo((ItemInfo) v.getTag());
         }
         logger.log(LAUNCHER_ALLAPPS_ITEM_LONG_PRESSED);
@@ -184,7 +188,7 @@
         // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
         if (launcher.getDragController().isDragging()) return false;
         // Return early if user is in the middle of selecting split-screen apps
-        if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionEnabled()) {
+        if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionActive()) {
             return false;
         }
 
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
deleted file mode 100644
index 51c047c..0000000
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.touch;
-
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.LEFT;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-
-import android.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.FloatProperty;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import com.android.launcher3.views.BaseDragLayer;
-
-import java.util.Collections;
-import java.util.List;
-
-public class LandscapePagedViewHandler implements PagedOrientationHandler {
-
-    @Override
-    public <T> T getPrimaryValue(T x, T y) {
-        return y;
-    }
-
-    @Override
-    public <T> T getSecondaryValue(T x, T y) {
-        return x;
-    }
-
-    @Override
-    public int getPrimaryValue(int x, int y) {
-        return y;
-    }
-
-    @Override
-    public int getSecondaryValue(int x, int y) {
-        return x;
-    }
-
-    @Override
-    public float getPrimaryValue(float x, float y) {
-        return y;
-    }
-
-    @Override
-    public float getSecondaryValue(float x, float y) {
-        return x;
-    }
-
-    @Override
-    public boolean isLayoutNaturalToLauncher() {
-        return false;
-    }
-
-    @Override
-    public void adjustFloatingIconStartVelocity(PointF velocity) {
-        float oldX = velocity.x;
-        float oldY = velocity.y;
-        velocity.set(-oldY, oldX);
-    }
-
-    @Override
-    public void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile) {
-        // We don't need to check the "top" value here because the startRect is in the orientation
-        // of the app, not of the fixed portrait launcher.
-        if (outStartRect.left > deviceProfile.heightPx) {
-            outStartRect.offsetTo(0, outStartRect.top);
-        } else if (outStartRect.left < -deviceProfile.heightPx) {
-            outStartRect.offsetTo(0, outStartRect.top);
-        }
-    }
-
-    @Override
-    public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
-        action.call(target, 0, param);
-    }
-
-    @Override
-    public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
-        action.call(target, 0, param);
-    }
-
-    @Override
-    public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
-        action.call(target, param, 0);
-    }
-
-    @Override
-    public <T> void set(T target, Int2DAction<T> action, int primaryParam,
-            int secondaryParam) {
-        action.call(target, secondaryParam, primaryParam);
-    }
-
-    @Override
-    public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
-        return event.getY(pointerIndex);
-    }
-
-    @Override
-    public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
-        return velocityTracker.getYVelocity(pointerId);
-    }
-
-    @Override
-    public int getMeasuredSize(View view) {
-        return view.getMeasuredHeight();
-    }
-
-    @Override
-    public int getPrimarySize(View view) {
-        return view.getHeight();
-    }
-
-    @Override
-    public float getPrimarySize(RectF rect) {
-        return rect.height();
-    }
-
-    @Override
-    public float getStart(RectF rect) {
-        return rect.top;
-    }
-
-    @Override
-    public float getEnd(RectF rect) {
-        return rect.bottom;
-    }
-
-    @Override
-    public int getClearAllSidePadding(View view, boolean isRtl) {
-        return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2;
-    }
-
-    @Override
-    public int getSecondaryDimension(View view) {
-        return view.getWidth();
-    }
-
-    @Override
-    public FloatProperty<View> getPrimaryViewTranslate() {
-        return VIEW_TRANSLATE_Y;
-    }
-
-    @Override
-    public FloatProperty<View> getSecondaryViewTranslate() {
-        return VIEW_TRANSLATE_X;
-    }
-
-    @Override
-    public int getPrimaryScroll(View view) {
-        return view.getScrollY();
-    }
-
-    @Override
-    public float getPrimaryScale(View view) {
-        return view.getScaleY();
-    }
-
-    @Override
-    public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
-        event.setMaxScrollY(maxScroll);
-    }
-
-    @Override
-    public boolean getRecentsRtlSetting(Resources resources) {
-        return !Utilities.isRtl(resources);
-    }
-
-    @Override
-    public float getDegreesRotated() {
-        return 90;
-    }
-
-    @Override
-    public int getRotation() {
-        return Surface.ROTATION_90;
-    }
-
-    @Override
-    public void setPrimaryScale(View view, float scale) {
-        view.setScaleY(scale);
-    }
-
-    @Override
-    public void setSecondaryScale(View view, float scale) {
-        view.setScaleX(scale);
-    }
-
-    @Override
-    public int getChildStart(View view) {
-        return view.getTop();
-    }
-
-    @Override
-    public int getCenterForPage(View view, Rect insets) {
-        return (view.getPaddingLeft() + view.getMeasuredWidth() + insets.left
-            - insets.right - view.getPaddingRight()) / 2;
-    }
-
-    @Override
-    public int getScrollOffsetStart(View view, Rect insets) {
-        return insets.top + view.getPaddingTop();
-    }
-
-    @Override
-    public int getScrollOffsetEnd(View view, Rect insets) {
-        return view.getHeight() - view.getPaddingBottom() - insets.bottom;
-    }
-
-    public int getSecondaryTranslationDirectionFactor() {
-        return 1;
-    }
-
-    @Override
-    public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
-        if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
-            return -1;
-        } else {
-            return 1;
-        }
-    }
-
-    @Override
-    public float getTaskMenuX(float x, View thumbnailView,
-            DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            return x + (taskInsetMargin / 2f);
-        }
-        return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
-    }
-
-    @Override
-    public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            return y - (thumbnailView.getLayoutDirection() == LAYOUT_DIRECTION_RTL
-                    ? taskMenuView.getMeasuredHeight() * 2 - (taskInsetMargin / 2f)
-                    : taskMenuView.getMeasuredHeight());
-
-        }
-        BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
-        int taskMenuWidth = lp.width;
-        if (stagePosition == STAGE_POSITION_UNDEFINED) {
-            return y + taskInsetMargin
-                    + (thumbnailView.getMeasuredHeight() - taskMenuWidth) / 2f;
-        } else {
-            return y + taskInsetMargin;
-        }
-    }
-
-    @Override
-    public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
-            @StagePosition int stagePosition) {
-        if (enableOverviewIconMenu()) {
-            return thumbnailView.getResources().getDimensionPixelSize(
-                    R.dimen.task_thumbnail_icon_menu_max_width);
-        }
-        if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_UNDEFINED) {
-            return thumbnailView.getMeasuredWidth();
-        } else {
-            return thumbnailView.getMeasuredHeight();
-        }
-    }
-
-    @Override
-    public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-            LinearLayout taskMenuLayout, int dividerSpacing,
-            ShapeDrawable dividerDrawable) {
-        taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
-        dividerDrawable.setIntrinsicHeight(dividerSpacing);
-        taskMenuLayout.setDividerDrawable(dividerDrawable);
-    }
-
-    @Override
-    public void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
-            LinearLayout viewGroup, DeviceProfile deviceProfile) {
-        // Phone fake landscape
-        viewGroup.setOrientation(LinearLayout.HORIZONTAL);
-        lp.width = MATCH_PARENT;
-        lp.height = WRAP_CONTENT;
-    }
-
-    @Override
-    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
-            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
-            View[] thumbnailViews, int desiredTaskId, View banner) {
-        boolean isRtl = banner.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        float translationX = 0;
-        float translationY = 0;
-        FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
-        banner.setPivotX(0);
-        banner.setPivotY(0);
-        banner.setRotation(getDegreesRotated());
-        translationX = banner.getHeight();
-        FrameLayout.LayoutParams snapshotParams =
-                (FrameLayout.LayoutParams) thumbnailViews[0]
-                        .getLayoutParams();
-        bannerParams.gravity = TOP | (isRtl ? END : START);
-        if (splitBounds == null) {
-            // Single, fullscreen case
-            bannerParams.width = taskViewHeight - snapshotParams.topMargin;
-            return new Pair<>(translationX, Integer.valueOf(snapshotParams.topMargin).floatValue());
-        }
-
-        // Set correct width
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[0].getMeasuredHeight();
-        } else {
-            bannerParams.width = thumbnailViews[1].getMeasuredHeight();
-        }
-
-        // Set translations
-        if (desiredTaskId == splitBounds.rightBottomTaskId) {
-            float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
-                    ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
-                    : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
-            translationY = snapshotParams.topMargin
-                    + ((taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent);
-        }
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            translationY = snapshotParams.topMargin;
-        }
-        return new Pair<>(translationX, translationY);
-    }
-
-    /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
-
-    @Override
-    public SingleAxisSwipeDetector.Direction getUpDownSwipeDirection() {
-        return HORIZONTAL;
-    }
-
-    @Override
-    public int getUpDirection(boolean isRtl) {
-        return isRtl ? SingleAxisSwipeDetector.DIRECTION_NEGATIVE
-                : SingleAxisSwipeDetector.DIRECTION_POSITIVE;
-    }
-
-    @Override
-    public boolean isGoingUp(float displacement, boolean isRtl) {
-        return isRtl ? displacement < 0 : displacement > 0;
-    }
-
-    @Override
-    public int getTaskDragDisplacementFactor(boolean isRtl) {
-        return isRtl ? 1 : -1;
-    }
-
-    /* -------------------- */
-
-    @Override
-    public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
-        boolean layoutChild) {
-        final int childHeight = child.getMeasuredHeight();
-        final int childBottom = childStart + childHeight;
-        final int childWidth = child.getMeasuredWidth();
-        final int childLeft = pageCenter - childWidth/ 2;
-        if (layoutChild) {
-            child.layout(childLeft, childStart, childLeft + childWidth, childBottom);
-        }
-        return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
-    }
-
-    @SuppressWarnings("SuspiciousNameCombination")
-    @Override
-    public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
-        return rect.left;
-    }
-
-    @Override
-    public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
-        // Add "left" side of phone which is actually the top
-        return Collections.singletonList(new SplitPositionOption(
-                R.drawable.ic_split_horizontal, R.string.recent_task_option_split_screen,
-                STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
-    }
-
-    @Override
-    public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
-            DeviceProfile dp, @StagePosition int stagePosition, Rect out) {
-        // In fake land/seascape, the placeholder always needs to go to the "top" of the device,
-        // which is the same bounds as 0 rotation.
-        int width = dp.widthPx;
-        int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp);
-        out.set(0, 0, width, placeholderHeight + insetSizeAdjustment);
-        out.inset(placeholderInset, 0);
-
-        // Adjust the top to account for content off screen. This will help to animate the view in
-        // with rounded corners.
-        int screenWidth = dp.widthPx;
-        int screenHeight = dp.heightPx;
-        int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset)
-                / screenWidth);
-        out.top -= (totalHeight - placeholderHeight);
-    }
-
-    @Override
-    public void updateSplitIconParams(View out, float onScreenRectCenterX,
-            float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
-            int drawableWidth, int drawableHeight, DeviceProfile dp,
-            @StagePosition int stagePosition) {
-        float insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f;
-        out.setX(onScreenRectCenterX / fullscreenScaleX
-                - 1.0f * drawableWidth / 2);
-        out.setY((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY
-                - 1.0f * drawableHeight / 2);
-    }
-
-    /**
-     * The split placeholder comes with a default inset to buffer the icon from the top of the
-     * screen. But if the device already has a large inset (from cutouts etc), use that instead.
-     */
-    private int getPlaceholderSizeAdjustment(DeviceProfile dp) {
-        return Math.max(dp.getInsets().top - dp.splitPlaceholderInset, 0);
-    }
-
-    @Override
-    public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
-            int splitInstructionsWidth) {
-        out.setPivotX(0);
-        out.setPivotY(splitInstructionsHeight);
-        out.setRotation(getDegreesRotated());
-        int distanceToEdge = out.getResources().getDimensionPixelSize(
-                R.dimen.split_instructions_bottom_margin_phone_landscape);
-        // Adjust for any insets on the left edge
-        int insetCorrectionX = dp.getInsets().left;
-        // Center the view in case of unbalanced insets on top or bottom of screen
-        int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
-        out.setTranslationX(distanceToEdge - insetCorrectionX);
-        out.setTranslationY(((-splitInstructionsHeight - splitInstructionsWidth) / 2f)
-                + insetCorrectionY);
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
-        // Setting gravity to LEFT instead of the lint-recommended START because we always want this
-        // view to be screen-left when phone is in landscape, regardless of the RtL setting.
-        lp.gravity = LEFT | CENTER_VERTICAL;
-        out.setLayoutParams(lp);
-    }
-
-    @Override
-    public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
-            @StagePosition int stagePosition, Rect out1, Rect out2) {
-        // In fake land/seascape, the window bounds are always top and bottom half
-        int screenHeight = dp.heightPx;
-        int screenWidth = dp.widthPx;
-        out1.set(0, 0, screenWidth, screenHeight / 2  - splitDividerSize);
-        out2.set(0, screenHeight / 2  + splitDividerSize, screenWidth, screenHeight);
-    }
-
-    @Override
-    public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
-            SplitBounds splitInfo, int desiredStagePosition) {
-        float topLeftTaskPercent = splitInfo.appsStackedVertically
-                ? splitInfo.topTaskPercent
-                : splitInfo.leftTaskPercent;
-        float dividerBarPercent = splitInfo.appsStackedVertically
-                ? splitInfo.dividerHeightPercent
-                : splitInfo.dividerWidthPercent;
-
-        if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
-            outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
-        } else {
-            outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
-        }
-    }
-
-    @Override
-    public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
-            int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp,
-            boolean isRtl) {
-        FrameLayout.LayoutParams primaryParams =
-                (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
-        FrameLayout.LayoutParams secondaryParams =
-                (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
-
-        // Swap the margins that are set in TaskView#setRecentsOrientedState()
-        secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx;
-        primaryParams.topMargin = 0;
-
-        // Measure and layout the thumbnails bottom up, since the primary is on the visual left
-        // (portrait bottom) and secondary is on the right (portrait top)
-        int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
-        int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
-        int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
-                ? splitBoundsConfig.dividerHeightPercent
-                : splitBoundsConfig.dividerWidthPercent));
-        int primarySnapshotHeight;
-        int primarySnapshotWidth;
-        int secondarySnapshotHeight;
-        int secondarySnapshotWidth;
-
-        float taskPercent = splitBoundsConfig.appsStackedVertically ?
-                splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent;
-        primarySnapshotWidth = parentWidth;
-        primarySnapshotHeight = (int) (totalThumbnailHeight * (taskPercent));
-
-        secondarySnapshotWidth = parentWidth;
-        secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
-        secondarySnapshot.setTranslationY(0);
-        primarySnapshot.setTranslationY(secondarySnapshotHeight + spaceAboveSnapshot + dividerBar);
-        primarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
-        secondarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
-                        View.MeasureSpec.EXACTLY));
-    }
-
-    @Override
-    public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
-            int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
-        if (enableOverviewIconMenu()) {
-            iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
-            iconParams.topMargin = 0;
-            return;
-        }
-        iconParams.gravity = (isRtl ? START : END) | CENTER_VERTICAL;
-        iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2;
-        iconParams.leftMargin = 0;
-        iconParams.topMargin = thumbnailTopMargin / 2;
-        iconParams.bottomMargin = 0;
-    }
-
-    @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
-            FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
-        boolean isRtl = iconAppChipMenuView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        iconMenuParams.gravity = (isRtl ? START : END) | (isRtl ? BOTTOM : TOP);
-        iconMenuParams.setMarginStart(isRtl ? iconMenuMargin : 0);
-        iconMenuParams.topMargin = iconMenuMargin;
-        iconMenuParams.bottomMargin = isRtl ? iconMenuMargin : 0;
-        iconMenuParams.setMarginEnd(iconMenuMargin);
-
-        iconAppChipMenuView.setPivotX(isRtl ? iconMenuParams.width - (iconMenuParams.height / 2f)
-                : iconMenuParams.width / 2f);
-        iconAppChipMenuView.setPivotY(
-                isRtl ? (iconMenuParams.height / 2f) : iconMenuParams.width / 2f);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
-    }
-
-    @Override
-    public void setSplitIconParams(View primaryIconView, View secondaryIconView,
-            int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
-            int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
-            DeviceProfile deviceProfile, SplitBounds splitConfig) {
-        FrameLayout.LayoutParams primaryIconParams =
-                (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
-        FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
-                ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
-                : new FrameLayout.LayoutParams(primaryIconParams);
-
-        // We calculate the "midpoint" of the thumbnail area, and place the icons there.
-        // This is the place where the thumbnail area splits by default, in a near-50/50 split.
-        // It is usually not exactly 50/50, due to insets/screen cutouts.
-        int fullscreenInsetThickness = deviceProfile.getInsets().top
-                - deviceProfile.getInsets().bottom;
-        int fullscreenMidpointFromBottom = ((deviceProfile.heightPx - fullscreenInsetThickness)
-                / 2);
-        float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
-        float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
-        int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
-        int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
-        int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
-        int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
-
-        if (enableOverviewIconMenu()) {
-            primaryIconParams.gravity = isRtl ? BOTTOM | START : TOP | END;
-            secondaryIconParams.gravity = isRtl ? BOTTOM | START : TOP | END;
-        } else {
-            primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
-            secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
-        }
-        primaryIconView.setTranslationX(0);
-        secondaryIconView.setTranslationX(0);
-        if (enableOverviewIconMenu()) {
-            if (primaryIconView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                secondaryIconView.setTranslationY(-primarySnapshotHeight);
-                primaryIconView.setTranslationY(0);
-            } else {
-                int secondarySnapshotHeight = groupedTaskViewHeight - primarySnapshotHeight;
-                primaryIconView.setTranslationY(secondarySnapshotHeight);
-            }
-        } else if (splitConfig.initiatedFromSeascape) {
-            // if the split was initiated from seascape,
-            // the task on the right (secondary) is slightly larger
-            primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
-            secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
-                    + taskIconHeight);
-        } else {
-            // if not,
-            // the task on the left (primary) is slightly larger
-            primaryIconView.setTranslationY(-bottomToMidpointOffset);
-            secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
-        }
-
-        primaryIconView.setLayoutParams(primaryIconParams);
-        secondaryIconView.setLayoutParams(secondaryIconParams);
-    }
-
-    @Override
-    public int getDefaultSplitPosition(DeviceProfile deviceProfile) {
-        throw new IllegalStateException("Default position not available in fake landscape");
-    }
-
-    @Override
-    public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
-            FloatProperty secondary, DeviceProfile deviceProfile) {
-        return new Pair<>(primary, secondary);
-    }
-
-    @Override
-    public float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
-            @StagePosition int stagePosition, DeviceProfile dp) {
-        float currentTranslationY = floatingTask.getTranslationY();
-        return currentTranslationY - onScreenRect.height();
-    }
-
-    @Override
-    public void setFloatingTaskPrimaryTranslation(View floatingTask, float translation,
-            DeviceProfile dp) {
-        floatingTask.setTranslationY(translation);
-    }
-
-    @Override
-    public Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
-        return floatingTask.getTranslationY();
-    }
-}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 74d88ba..e0c4e3c 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -19,26 +19,11 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.FloatProperty;
-import android.util.Pair;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-
-import java.util.List;
 
 /**
  * Abstraction layer to separate horizontal and vertical specific implementations
@@ -47,9 +32,7 @@
  */
 public interface PagedOrientationHandler {
 
-    PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
-    PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
-    PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
+    PagedOrientationHandler DEFAULT = new DefaultPagedViewHandler();
 
     interface Int2DAction<T> {
         void call(T target, int x, int y);
@@ -64,39 +47,18 @@
 
     <T> void setPrimary(T target, Int2DAction<T> action, int param);
     <T> void setPrimary(T target, Float2DAction<T> action, float param);
-    <T> void setSecondary(T target, Float2DAction<T> action, float param);
-    <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
     float getPrimaryDirection(MotionEvent event, int pointerIndex);
     float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
     int getMeasuredSize(View view);
-    int getPrimarySize(View view);
-    float getPrimarySize(RectF rect);
-    float getStart(RectF rect);
-    float getEnd(RectF rect);
-    int getClearAllSidePadding(View view, boolean isRtl);
-    int getSecondaryDimension(View view);
-    FloatProperty<View> getPrimaryViewTranslate();
-    FloatProperty<View> getSecondaryViewTranslate();
-
     int getPrimaryScroll(View view);
     float getPrimaryScale(View view);
     int getChildStart(View view);
     int getCenterForPage(View view, Rect insets);
     int getScrollOffsetStart(View view, Rect insets);
     int getScrollOffsetEnd(View view, Rect insets);
-    int getSecondaryTranslationDirectionFactor();
-    int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
-            DeviceProfile deviceProfile);
     ChildBounds getChildBounds(View child, int childStart, int pageCenter, boolean layoutChild);
     void setMaxScroll(AccessibilityEvent event, int maxScroll);
     boolean getRecentsRtlSetting(Resources resources);
-    float getDegreesRotated();
-    int getRotation();
-    void setPrimaryScale(View view, float scale);
-    void setSecondaryScale(View view, float scale);
-
-    <T> T getPrimaryValue(T x, T y);
-    <T> T getSecondaryValue(T x, T y);
 
     int getPrimaryValue(int x, int y);
     int getSecondaryValue(int x, int y);
@@ -104,174 +66,6 @@
     float getPrimaryValue(float x, float y);
     float getSecondaryValue(float x, float y);
 
-    boolean isLayoutNaturalToLauncher();
-    Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
-            FloatProperty secondary, DeviceProfile deviceProfile);
-    int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
-    List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
-    /**
-     * @param placeholderHeight height of placeholder view in portrait, width in landscape
-     */
-    void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
-            DeviceProfile dp, @StagePosition int stagePosition, Rect out);
-
-    /**
-     * Centers an icon in the split staging area, accounting for insets.
-     * @param out The icon that needs to be centered.
-     * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
-     *                        offscreen).
-     * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
-     *                        offscreen).
-     * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
-     * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
-     * @param drawableWidth The icon's drawable (final) width.
-     * @param drawableHeight The icon's drawable (final) height.
-     * @param dp The device profile, used to report rotation and hardware insets.
-     * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
-     */
-    void updateSplitIconParams(View out, float onScreenRectCenterX,
-            float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
-            int drawableWidth, int drawableHeight, DeviceProfile dp,
-            @StagePosition int stagePosition);
-
-    /**
-     * Sets positioning and rotation for a SplitInstructionsView.
-     * @param out The SplitInstructionsView that needs to be positioned.
-     * @param dp The device profile, used to report rotation and device type.
-     * @param splitInstructionsHeight The SplitInstructionView's height.
-     * @param splitInstructionsWidth  The SplitInstructionView's width.
-     */
-    void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
-            int splitInstructionsWidth);
-
-    /**
-     * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
-     * @param stagePosition the split position option (top/left, bottom/right) of the first
-     *                           task selected for entering split
-     * @param out1 the bounds for where the first selected app will be
-     * @param out2 the bounds for where the second selected app will be, complimentary to
-     *             {@param out1} based on {@param initialSplitOption}
-     */
-    void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
-            @StagePosition int stagePosition, Rect out1, Rect out2);
-
-    int getDefaultSplitPosition(DeviceProfile deviceProfile);
-
-    /**
-     * @param outRect This is expected to be the rect that has the dimensions for a non-split,
-     *                fullscreen task in overview. This will directly be modified.
-     * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
-     *                           outRect for
-     */
-    void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
-            @SplitConfigurationOptions.StagePosition int desiredStagePosition);
-
-    void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
-            int parentWidth, int parentHeight,
-            SplitBounds splitBoundsConfig, DeviceProfile dp, boolean isRtl);
-
-    // Overview TaskMenuView methods
-    void setTaskIconParams(FrameLayout.LayoutParams iconParams,
-            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
-    void setIconAppChipMenuParams(View iconAppChipMenuView, FrameLayout.LayoutParams iconMenuParams,
-            int iconMenuMargin, int thumbnailTopMargin);
-    void setSplitIconParams(View primaryIconView, View secondaryIconView,
-            int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
-            int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
-            DeviceProfile deviceProfile, SplitBounds splitConfig);
-
-    /*
-     * The following two methods try to center the TaskMenuView in landscape by finding the center
-     * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
-     * taskMenu width is the same size as the thumbnail width (what got set below in
-     * getTaskMenuWidth()), so we directly use that in the calculations.
-     */
-    float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
-            float taskInsetMargin, View taskViewIcon);
-    float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin, View taskViewIcon);
-    int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
-            @StagePosition int stagePosition);
-    /**
-     * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
-     * inside task menu view.
-     */
-    void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
-            LinearLayout taskMenuLayout, int dividerSpacing,
-            ShapeDrawable dividerDrawable);
-    /**
-     * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
-     * views inside task menu view.
-     */
-    void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
-            LinearLayout viewGroup, DeviceProfile deviceProfile);
-
-    /**
-     * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
-     * TaskView.
-     * @return A Pair of Floats representing the proper x and y translations.
-     */
-    Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
-            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
-            View[] thumbnailViews, int desiredTaskId, View banner);
-
-    // The following are only used by TaskViewTouchHandler.
-    /** @return Either VERTICAL or HORIZONTAL. */
-    SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
-    /** @return Given {@link #getUpDownSwipeDirection()}, whether POSITIVE or NEGATIVE is up. */
-    int getUpDirection(boolean isRtl);
-    /** @return Whether the displacement is going towards the top of the screen. */
-    boolean isGoingUp(float displacement, boolean isRtl);
-    /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
-    int getTaskDragDisplacementFactor(boolean isRtl);
-
-    /**
-     * Maps the velocity from the coordinate plane of the foreground app to that
-     * of Launcher's (which now will always be portrait)
-     */
-    void adjustFloatingIconStartVelocity(PointF velocity);
-
-    /**
-     * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
-     * @param outStartRect The start rect that will directly be modified
-     */
-    void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile);
-
-    /**
-     * Determine the target translation for animating the FloatingTaskView out. This value could
-     * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
-     * docked.
-     *
-     * @param floatingTask The FloatingTaskView.
-     * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
-     * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
-     * @param dp The device profile.
-     * @return A float. When an animation translates the FloatingTaskView to this position, it will
-     * appear to tuck away off the edge of the screen.
-     */
-    float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
-            @StagePosition int stagePosition, DeviceProfile dp);
-
-    /**
-     * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
-     * either x or y), depending on how the view is oriented.
-     *
-     * @param floatingTask The FloatingTaskView to be translated.
-     * @param translation The target translation value.
-     * @param dp The current device profile.
-     */
-    void setFloatingTaskPrimaryTranslation(View floatingTask, float translation, DeviceProfile dp);
-
-    /**
-     * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
-     * either x or y), depending on how the view is oriented.
-     *
-     * @param floatingTask The FloatingTaskView in question.
-     * @param dp The current device profile.
-     * @return The current translation value.
-     */
-    Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp);
-
     class ChildBounds {
 
         public final int primaryDimension;
@@ -279,8 +73,8 @@
         public final int childPrimaryEnd;
         public final int childSecondaryEnd;
 
-        ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
-            int childSecondaryEnd) {
+        public ChildBounds(int primaryDimension, int secondaryDimension, int childPrimaryEnd,
+                int childSecondaryEnd) {
             this.primaryDimension = primaryDimension;
             this.secondaryDimension = secondaryDimension;
             this.childPrimaryEnd = childPrimaryEnd;
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
deleted file mode 100644
index 06526a8..0000000
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.touch;
-
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.RIGHT;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-
-import android.content.res.Resources;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.Surface;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.views.BaseDragLayer;
-
-import java.util.Collections;
-import java.util.List;
-
-public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
-
-    @Override
-    public int getSecondaryTranslationDirectionFactor() {
-        return -1;
-    }
-
-    @Override
-    public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
-        if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
-            return -1;
-        } else {
-            return 1;
-        }
-    }
-
-    @Override
-    public boolean getRecentsRtlSetting(Resources resources) {
-        return Utilities.isRtl(resources);
-    }
-
-    @Override
-    public float getDegreesRotated() {
-        return 270;
-    }
-
-    @Override
-    public int getRotation() {
-        return Surface.ROTATION_270;
-    }
-
-    @Override
-    public void adjustFloatingIconStartVelocity(PointF velocity) {
-        float oldX = velocity.x;
-        float oldY = velocity.y;
-        velocity.set(oldY, -oldX);
-    }
-
-    @Override
-    public float getTaskMenuX(float x, View thumbnailView,
-            DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            return x + (taskViewIcon.getHeight() * 2);
-        }
-        return x + taskInsetMargin;
-    }
-
-    @Override
-    public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
-            View taskMenuView, float taskInsetMargin, View taskViewIcon) {
-        if (enableOverviewIconMenu()) {
-            return y + taskViewIcon.getWidth() + (
-                    thumbnailView.getLayoutDirection() == LAYOUT_DIRECTION_RTL ? taskInsetMargin
-                            / 2f : -taskViewIcon.getHeight());
-        }
-        BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
-        int taskMenuWidth = lp.width;
-        if (stagePosition == STAGE_POSITION_UNDEFINED) {
-            return y + taskInsetMargin
-                    + (thumbnailView.getMeasuredHeight() + taskMenuWidth) / 2f;
-        } else {
-            return y + taskMenuWidth + taskInsetMargin;
-        }
-    }
-
-    @Override
-    public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
-            int desiredStagePosition) {
-        float topLeftTaskPercent = splitInfo.appsStackedVertically
-                ? splitInfo.topTaskPercent
-                : splitInfo.leftTaskPercent;
-        float dividerBarPercent = splitInfo.appsStackedVertically
-                ? splitInfo.dividerHeightPercent
-                : splitInfo.dividerWidthPercent;
-
-        // In seascape, the primary thumbnail is counterintuitively placed at the physical bottom of
-        // the screen. This is to preserve consistency when the user rotates: From the user's POV,
-        // the primary should always be on the left.
-        if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
-            outRect.top += (int) (outRect.height() * ((1 - topLeftTaskPercent)));
-        } else {
-            outRect.bottom -= (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
-        }
-    }
-
-    @Override
-    public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
-            int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
-            View[] thumbnailViews, int desiredTaskId, View banner) {
-        boolean isRtl = banner.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        float translationX = 0;
-        float translationY = 0;
-        FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
-        banner.setPivotX(0);
-        banner.setPivotY(0);
-        banner.setRotation(getDegreesRotated());
-        translationX = taskViewWidth - banner.getHeight();
-        FrameLayout.LayoutParams snapshotParams =
-                (FrameLayout.LayoutParams) thumbnailViews[0]
-                        .getLayoutParams();
-        bannerParams.gravity = BOTTOM | (isRtl ? END : START);
-
-        if (splitBounds == null) {
-            // Single, fullscreen case
-            bannerParams.width = taskViewHeight - snapshotParams.topMargin;
-            translationY = banner.getHeight();
-            return new Pair<>(translationX, translationY);
-        }
-
-        // Set correct width
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            bannerParams.width = thumbnailViews[0].getMeasuredHeight();
-        } else {
-            bannerParams.width = thumbnailViews[1].getMeasuredHeight();
-        }
-
-        // Set translations
-        if (desiredTaskId == splitBounds.rightBottomTaskId) {
-            translationY = banner.getHeight();
-        }
-        if (desiredTaskId == splitBounds.leftTopTaskId) {
-            float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
-                    ? (1f - splitBounds.topTaskPercent)
-                    : (1f - splitBounds.leftTaskPercent);
-            translationY = banner.getHeight()
-                    - ((taskViewHeight - snapshotParams.topMargin)
-                    * bottomRightTaskPlusDividerPercent);
-        }
-        return new Pair<>(translationX, translationY);
-    }
-
-    @Override
-    public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
-        return dp.widthPx - rect.right;
-    }
-
-    @Override
-    public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
-        // Add "right" option which is actually the top
-        return Collections.singletonList(new SplitPositionOption(
-                R.drawable.ic_split_horizontal, R.string.recent_task_option_split_screen,
-                STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
-    }
-
-    @Override
-    public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
-            int splitInstructionsWidth) {
-        out.setPivotX(0);
-        out.setPivotY(splitInstructionsHeight);
-        out.setRotation(getDegreesRotated());
-        int distanceToEdge = out.getResources().getDimensionPixelSize(
-                R.dimen.split_instructions_bottom_margin_phone_landscape);
-        // Adjust for any insets on the right edge
-        int insetCorrectionX = dp.getInsets().right;
-        // Center the view in case of unbalanced insets on top or bottom of screen
-        int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
-        out.setTranslationX(splitInstructionsWidth - distanceToEdge + insetCorrectionX);
-        out.setTranslationY(((-splitInstructionsHeight + splitInstructionsWidth) / 2f)
-                + insetCorrectionY);
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
-        // Setting gravity to RIGHT instead of the lint-recommended END because we always want this
-        // view to be screen-right when phone is in seascape, regardless of the RtL setting.
-        lp.gravity = RIGHT | CENTER_VERTICAL;
-        out.setLayoutParams(lp);
-    }
-
-    @Override
-    public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
-            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
-        iconParams.rightMargin = 0;
-        iconParams.bottomMargin = 0;
-        if (enableOverviewIconMenu()) {
-            iconParams.setMarginStart(taskIconMargin);
-            iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
-            iconParams.leftMargin = 0;
-            iconParams.topMargin = 0;
-        } else {
-            iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
-            iconParams.leftMargin = -taskIconHeight - taskIconMargin / 2;
-            iconParams.topMargin = thumbnailTopMargin / 2;
-        }
-    }
-
-    @Override
-    public void setIconAppChipMenuParams(View iconAppChipMenuView,
-            FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
-        boolean isRtl = iconAppChipMenuView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        iconMenuParams.gravity = (isRtl ? TOP : BOTTOM) | (isRtl ? END : START);
-        iconMenuParams.setMarginStart(0);
-        iconMenuParams.topMargin = isRtl ? iconMenuMargin : 0;
-        iconMenuParams.bottomMargin = 0;
-        iconMenuParams.setMarginEnd(isRtl ? thumbnailTopMargin : 0);
-
-        // Use half menu height to place the pivot within the X/Y center of icon in the menu.
-        float iconCenter = iconAppChipMenuView.getHeight() / 2f;
-        iconAppChipMenuView.setPivotX(isRtl ? iconMenuParams.width / 2f : iconCenter);
-        iconAppChipMenuView.setPivotY(
-                isRtl ? iconMenuParams.width / 2f : iconCenter - iconMenuMargin);
-        iconAppChipMenuView.setTranslationY(0);
-        iconAppChipMenuView.setRotation(getDegreesRotated());
-    }
-
-    @Override
-    public void setSplitIconParams(View primaryIconView, View secondaryIconView,
-            int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
-            int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
-            DeviceProfile deviceProfile, SplitBounds splitConfig) {
-        super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
-                primarySnapshotWidth, primarySnapshotHeight, groupedTaskViewHeight,
-                groupedTaskViewWidth, isRtl, deviceProfile, splitConfig);
-        FrameLayout.LayoutParams primaryIconParams =
-                (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
-        FrameLayout.LayoutParams secondaryIconParams =
-                (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
-
-        // We calculate the "midpoint" of the thumbnail area, and place the icons there.
-        // This is the place where the thumbnail area splits by default, in a near-50/50 split.
-        // It is usually not exactly 50/50, due to insets/screen cutouts.
-        int fullscreenInsetThickness = deviceProfile.getInsets().top
-                - deviceProfile.getInsets().bottom;
-        int fullscreenMidpointFromBottom = ((deviceProfile.heightPx
-                - fullscreenInsetThickness) / 2);
-        float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
-        float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
-        int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
-        int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
-        int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
-        int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
-
-        int gravity = (isRtl ? TOP : BOTTOM) | (isRtl ? END : START);
-        primaryIconParams.gravity = gravity;
-        secondaryIconParams.gravity = gravity;
-        primaryIconView.setTranslationX(0);
-        secondaryIconView.setTranslationX(0);
-        if (enableOverviewIconMenu()) {
-            if (primaryIconView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
-                primaryIconView.setTranslationY(groupedTaskViewHeight - primarySnapshotHeight);
-                secondaryIconView.setTranslationY(0);
-            } else {
-                secondaryIconView.setTranslationY(-primarySnapshotHeight);
-                primaryIconView.setTranslationY(0);
-            }
-        } else if (splitConfig.initiatedFromSeascape) {
-            // if the split was initiated from seascape,
-            // the task on the right (secondary) is slightly larger
-            primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
-                    + taskIconHeight);
-            secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
-        } else {
-            // if not,
-            // the task on the left (primary) is slightly larger
-            primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
-            secondaryIconView.setTranslationY(-bottomToMidpointOffset);
-        }
-
-        primaryIconView.setLayoutParams(primaryIconParams);
-        secondaryIconView.setLayoutParams(secondaryIconParams);
-    }
-
-    @Override
-    public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
-            int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp,
-            boolean isRtl) {
-        FrameLayout.LayoutParams primaryParams =
-                (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
-        FrameLayout.LayoutParams secondaryParams =
-                (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
-
-        // Swap the margins that are set in TaskView#setRecentsOrientedState()
-        secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx;
-        primaryParams.topMargin = 0;
-
-        // Measure and layout the thumbnails bottom up, since the primary is on the visual left
-        // (portrait bottom) and secondary is on the right (portrait top)
-        int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
-        int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
-        int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
-                ? splitBoundsConfig.dividerHeightPercent
-                : splitBoundsConfig.dividerWidthPercent));
-        int primarySnapshotHeight;
-        int primarySnapshotWidth;
-        int secondarySnapshotHeight;
-        int secondarySnapshotWidth;
-
-        float taskPercent = splitBoundsConfig.appsStackedVertically ?
-                splitBoundsConfig.topTaskPercent : splitBoundsConfig.leftTaskPercent;
-        primarySnapshotWidth = parentWidth;
-        primarySnapshotHeight = (int) (totalThumbnailHeight * (taskPercent));
-
-        secondarySnapshotWidth = parentWidth;
-        secondarySnapshotHeight = totalThumbnailHeight - primarySnapshotHeight - dividerBar;
-        secondarySnapshot.setTranslationY(0);
-        primarySnapshot.setTranslationY(secondarySnapshotHeight + spaceAboveSnapshot + dividerBar);
-        primarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(primarySnapshotHeight, View.MeasureSpec.EXACTLY));
-        secondarySnapshot.measure(
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotWidth, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(secondarySnapshotHeight,
-                        View.MeasureSpec.EXACTLY));
-    }
-
-    /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
-
-    @Override
-    public SingleAxisSwipeDetector.Direction getUpDownSwipeDirection() {
-        return HORIZONTAL;
-    }
-
-    @Override
-    public int getUpDirection(boolean isRtl) {
-        return isRtl ? SingleAxisSwipeDetector.DIRECTION_POSITIVE
-                : SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
-    }
-
-    @Override
-    public boolean isGoingUp(float displacement, boolean isRtl) {
-        return isRtl ? displacement > 0 : displacement < 0;
-    }
-
-    @Override
-    public int getTaskDragDisplacementFactor(boolean isRtl) {
-        return isRtl ? -1 : 1;
-    }
-
-    /* -------------------- */
-}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 5b6c9e0..0ff10c2 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -24,6 +24,7 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_CLOSE_TAP_OUTSIDE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORKSPACE_LONGPRESS;
 
 import android.graphics.PointF;
@@ -206,8 +207,8 @@
                         HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                 mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
                 mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
-                if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionEnabled()) {
-                    mLauncher.dismissSplitSelection();
+                if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionActive()) {
+                    mLauncher.dismissSplitSelection(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
                 }
             } else {
                 cancelLongPress();
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 7af1a13..b2d0d75 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,13 +15,14 @@
  */
 package com.android.launcher3.util;
 
+import android.util.Log;
+
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseActivity;
 
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -30,6 +31,8 @@
  */
 public final class ActivityTracker<T extends BaseActivity> {
 
+    private static final String TAG = "ActivityTracker";
+
     private WeakReference<T> mCurrentActivity = new WeakReference<>(null);
     private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>();
 
@@ -53,12 +56,13 @@
      *
      * @param callback The callback to call init() on when the activity is ready.
      */
-    public void registerCallback(SchedulerCallback<T> callback) {
+    public void registerCallback(SchedulerCallback<T> callback, String reasonString) {
+        Log.d(TAG, "Registering callback: " + callback + ", reason=" + reasonString);
         T activity = mCurrentActivity.get();
         mCallbacks.add(callback);
         if (activity != null) {
             if (!callback.init(activity, activity.isStarted())) {
-                unregisterCallback(callback);
+                unregisterCallback(callback, "ActivityTracker.registerCallback: Intent handled");
             }
         }
     }
@@ -66,7 +70,8 @@
     /**
      * Unregisters a registered callback.
      */
-    public void unregisterCallback(SchedulerCallback<T> callback) {
+    public void unregisterCallback(SchedulerCallback<T> callback, String reasonString) {
+        Log.d(TAG, "Unregistering callback: " + callback + ", reason=" + reasonString);
         mCallbacks.remove(callback);
     }
 
@@ -81,16 +86,25 @@
 
     private boolean handleIntent(T activity, boolean alreadyOnHome) {
         boolean handled = false;
+        if (!mCallbacks.isEmpty()) {
+            Log.d(TAG, "handleIntent: mCallbacks=" + mCallbacks);
+        }
         for (SchedulerCallback<T> cb : mCallbacks) {
             if (!cb.init(activity, alreadyOnHome)) {
                 // Callback doesn't want any more updates
-                unregisterCallback(cb);
+                unregisterCallback(cb, "ActivityTracker.handleIntent: Intent handled");
             }
             handled = true;
         }
         return handled;
     }
 
+    public void dump(String prefix, PrintWriter writer) {
+        writer.println(prefix + "ActivityTracker:");
+        writer.println(prefix + "\tmCurrentActivity=" + mCurrentActivity.get());
+        writer.println(prefix + "\tmCallbacks=" + mCallbacks);
+    }
+
     public interface SchedulerCallback<T extends BaseActivity> {
 
         /**
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
new file mode 100644
index 0000000..6429a43
--- /dev/null
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import android.app.ActivityOptions;
+import android.app.Person;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.ArrayMap;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A wrapper for the hidden API calls
+ */
+public class ApiWrapper implements ResourceBasedOverride, SafeCloseable {
+
+    public static final MainThreadInitializedObject<ApiWrapper> INSTANCE =
+            forOverride(ApiWrapper.class, R.string.api_wrapper_class);
+
+    protected final Context mContext;
+
+    public ApiWrapper(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Returns the list of persons associated with the provided shortcut info
+     */
+    public Person[] getPersons(ShortcutInfo si) {
+        return Utilities.EMPTY_PERSON_ARRAY;
+    }
+
+    public Map<String, LauncherActivityInfo> getActivityOverrides() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Creates an ActivityOptions to play fade-out animation on closing targets
+     */
+    public ActivityOptions createFadeOutAnimOptions() {
+        return ActivityOptions.makeCustomAnimation(mContext, 0, android.R.anim.fade_out);
+    }
+
+    /**
+     * Returns a map of all users on the device to their corresponding UI properties
+     */
+    public Map<UserHandle, UserIconInfo> queryAllUsers() {
+        UserManager um = mContext.getSystemService(UserManager.class);
+        Map<UserHandle, UserIconInfo> users = new ArrayMap<>();
+        List<UserHandle> usersActual = um.getUserProfiles();
+        if (usersActual != null) {
+            for (UserHandle user : usersActual) {
+                long serial = um.getSerialNumberForUser(user);
+
+                // Simple check to check if the provided user is work profile
+                // TODO: Migrate to a better platform API
+                NoopDrawable d = new NoopDrawable();
+                boolean isWork = (d != mContext.getPackageManager().getUserBadgedIcon(d, user));
+                UserIconInfo info = new UserIconInfo(
+                        user,
+                        isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN,
+                        serial);
+                users.put(user, info);
+            }
+        }
+        return users;
+    }
+
+    /**
+     * Returns the list of the system packages that are installed at user creation.
+     * An empty list denotes that all system packages are installed for that user at creation.
+     */
+    public List<String> getPreInstalledSystemPackages(UserHandle user) {
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns an intent which can be used to start the App Market activity (Installer
+     * Activity).
+     */
+    public Intent getAppMarketActivityIntent(String packageName, UserHandle user) {
+        return new Intent(Intent.ACTION_VIEW)
+                .setData(new Uri.Builder()
+                        .scheme("market")
+                        .authority("details")
+                        .appendQueryParameter("id", packageName)
+                        .build())
+                .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
+                        .authority(BuildConfig.APPLICATION_ID).build());
+    }
+
+    /**
+     * Returns an intent which can be used to open Private Space Settings.
+     */
+    @Nullable
+    public Intent getPrivateSpaceSettingsIntent() {
+        return null;
+    }
+
+    /**
+     * Checks if an activity is flagged as non-resizeable.
+     */
+    public boolean isNonResizeableActivity(LauncherActivityInfo lai) {
+        // Overridden in quickstep
+        return false;
+    }
+
+    @Override
+    public void close() { }
+
+    private static class NoopDrawable extends ColorDrawable {
+        @Override
+        public int getIntrinsicHeight() {
+            return 1;
+        }
+
+        @Override
+        public int getIntrinsicWidth() {
+            return 1;
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java
deleted file mode 100644
index adc3c7d..0000000
--- a/src/com/android/launcher3/util/BgObjectWithLooper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util;
-
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.annotation.WorkerThread;
-
-import java.util.function.Consumer;
-
-/**
- * Utility class to define an object which does most of it's processing on a
- * dedicated background thread.
- */
-public abstract class BgObjectWithLooper {
-
-    /**
-     * Start initialization of the object
-     */
-    public final void initializeInBackground(String threadName) {
-        new Thread(this::runOnThread, threadName).start();
-    }
-
-    private void runOnThread() {
-        Looper.prepare();
-        onInitialized(Looper.myLooper());
-        Looper.loop();
-    }
-
-    /**
-     * Called on the background thread to handle initialization
-     */
-    @WorkerThread
-    protected abstract void onInitialized(Looper looper);
-
-    /**
-     * Helper method to create a content provider
-     */
-    protected static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) {
-        return new ContentObserver(handler) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                command.accept(uri);
-            }
-        };
-    }
-}
diff --git a/src/com/android/launcher3/util/CancellableTask.kt b/src/com/android/launcher3/util/CancellableTask.kt
new file mode 100644
index 0000000..49ef020
--- /dev/null
+++ b/src/com/android/launcher3/util/CancellableTask.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import java.util.concurrent.Executor
+import java.util.function.Consumer
+import java.util.function.Supplier
+
+/** A [Runnable] that can be posted to a [Executor] that can be cancelled. */
+class CancellableTask<T>
+@JvmOverloads
+constructor(
+    private val task: Supplier<T>,
+    // Executor where consumer needs to be executed on. Typically UI executor.
+    private val callbackExecutor: Executor,
+    // Consumer that needs to be accepted upon completion of the task. Typically work that needs to
+    // be done in UI thread after task completes.
+    private val callback: Consumer<T>,
+    // Callback to be executed on callbackExecutor at the end irrespective of the task being
+    // completed or cancelled
+    private val endRunnable: Runnable = Runnable {}
+) : Runnable {
+
+    // flag to cancel the callback
+    var canceled = false
+        private set
+
+    private var ended = false
+
+    override fun run() {
+        if (canceled) return
+        val value = task.get()
+        callbackExecutor.execute {
+            if (!canceled) {
+                callback.accept(value)
+            }
+            onEnd()
+        }
+    }
+
+    /**
+     * Cancel the [CancellableTask] if not scheduled. If [CancellableTask] has started execution at
+     * this time, we will try to cancel the callback if not executed yet.
+     */
+    fun cancel() {
+        canceled = true
+        callbackExecutor.execute(this::onEnd)
+    }
+
+    private fun onEnd() {
+        if (!ended) {
+            ended = true
+            endRunnable.run()
+        }
+    }
+}
diff --git a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
index 18f8339..85f81f5 100644
--- a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
+++ b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
@@ -26,6 +26,8 @@
 import com.android.launcher3.anim.AnimatorPlaybackController
 import com.android.launcher3.anim.PendingAnimation
 import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.states.StateAnimationConfig.HANDLE_STATE_APPLY
+import com.android.launcher3.states.StateAnimationConfig.USER_CONTROLLED
 import java.util.function.Consumer
 
 private const val TAG = "CannedAnimCoordinator"
@@ -107,8 +109,15 @@
         }
         // Link this to the state manager so that it auto-cancels when state changes
         recreatePending = false
+        // Animator coordinator takes care of reapplying the animation due to state reset. Set the
+        // flags accordingly
         animationController =
-            controller.apply { activity.stateManager.setCurrentUserControlledAnimation(this) }
+            controller.apply {
+                activity.stateManager.setCurrentAnimation(
+                    this,
+                    USER_CONTROLLED or HANDLE_STATE_APPLY
+                )
+            }
         recreateAnimation(provider)
     }
 
diff --git a/src/com/android/launcher3/util/CellContentDimensions.kt b/src/com/android/launcher3/util/CellContentDimensions.kt
index 3c8e0c4..5059c2f 100644
--- a/src/com/android/launcher3/util/CellContentDimensions.kt
+++ b/src/com/android/launcher3/util/CellContentDimensions.kt
@@ -48,7 +48,10 @@
             cellContentHeight = getCellContentHeight()
 
             // Step 3. Decrease label size
-            if (cellContentHeight > cellHeightPx) {
+            if (
+                cellContentHeight > cellHeightPx &&
+                    iconTextSizePx > iconSizeSteps.minimumIconLabelSize
+            ) {
                 iconTextSizePx =
                     max(
                         iconSizeSteps.minimumIconLabelSize,
@@ -58,6 +61,17 @@
             }
         }
 
+        // For some cases, depending on the display size, the content might not fit inside the
+        // cell height after considering the minimum icon and label size allowed.
+        // For these extreme cases, we will allow the icon size to be smaller than
+        // [IconSizeSteps.minimumIconSize] to fit inside the cell height without cropping.
+        while (
+            cellContentHeight > cellHeightPx && iconSizePx > IconSizeSteps.ICON_SIZE_STEP_EXTRA
+        ) {
+            iconSizePx -= IconSizeSteps.ICON_SIZE_STEP_EXTRA
+            cellContentHeight = getCellContentHeight()
+        }
+
         return cellContentHeight
     }
 
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 18f583d..8806e27 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -19,6 +19,9 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
 import static com.android.launcher3.Utilities.dpiFromPx;
@@ -47,6 +50,7 @@
 import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.InvariantDeviceProfile.DeviceType;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
@@ -175,6 +179,13 @@
         sTransientTaskbarStatusForTests = enable;
     }
 
+    /**
+     * Returns whether the taskbar is pinned in gesture navigation mode.
+     */
+    public static boolean isPinnedTaskbar(Context context) {
+        return INSTANCE.get(context).getInfo().isPinnedTaskbar();
+    }
+
     @Override
     public void close() {
         mDestroyed = true;
@@ -355,10 +366,10 @@
                 WindowManagerProxy wmProxy,
                 Map<CachedDisplayInfo, List<WindowBounds>> perDisplayBoundsCache) {
             CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(displayInfoContext);
-            normalizedDisplayInfo = displayInfo.normalize();
+            normalizedDisplayInfo = displayInfo.normalize(wmProxy);
             rotation = displayInfo.rotation;
             currentSize = displayInfo.size;
-            cutout = displayInfo.cutout;
+            cutout = WindowManagerProxy.getSafeInsets(displayInfo.cutout);
 
             Configuration config = displayInfoContext.getResources().getConfiguration();
             fontScale = config.fontScale;
@@ -423,6 +434,12 @@
             }
             return true;
         }
+        /**
+         * Returns whether the taskbar is pinned in gesture navigation mode.
+         */
+        public boolean isPinnedTaskbar() {
+            return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar();
+        }
 
         /**
          * Returns {@code true} if the bounds represent a tablet.
@@ -453,6 +470,23 @@
         public int getDensityDpi() {
             return densityDpi;
         }
+
+        public @DeviceType int getDeviceType() {
+            int flagPhone = 1 << 0;
+            int flagTablet = 1 << 1;
+
+            int type = supportedBounds.stream()
+                    .mapToInt(bounds -> isTablet(bounds) ? flagTablet : flagPhone)
+                    .reduce(0, (a, b) -> a | b);
+            if (type == (flagPhone | flagTablet)) {
+                // device has profiles supporting both phone and tablet modes
+                return TYPE_MULTI_DISPLAY;
+            } else if (type == flagTablet) {
+                return TYPE_TABLET;
+            } else {
+                return TYPE_PHONE;
+            }
+        }
     }
 
     /**
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index e6ee186..fbdb5c2 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -22,7 +22,6 @@
 import androidx.annotation.FractionRes;
 import androidx.annotation.IntegerRes;
 
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.ResourceProvider;
 
@@ -34,7 +33,8 @@
  *
  * To allow customization for a particular resource, add them to dynamic_resources.xml
  */
-public class DynamicResource implements ResourceProvider, PluginListener<ResourceProvider> {
+public class DynamicResource implements
+        ResourceProvider, PluginListener<ResourceProvider>, SafeCloseable {
 
     private static final MainThreadInitializedObject<DynamicResource> INSTANCE =
             new MainThreadInitializedObject<>(DynamicResource::new);
@@ -49,6 +49,11 @@
     }
 
     @Override
+    public void close() {
+        PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
+    }
+
+    @Override
     public int getInt(@IntegerRes int resId) {
         return mContext.getResources().getInteger(resId);
     }
diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java
index 491582b..ca37259 100644
--- a/src/com/android/launcher3/util/EdgeEffectCompat.java
+++ b/src/com/android/launcher3/util/EdgeEffectCompat.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.util;
 
 import android.content.Context;
+import android.view.MotionEvent;
 import android.widget.EdgeEffect;
 
 import com.android.launcher3.Utilities;
@@ -43,4 +44,14 @@
             return deltaDistance;
         }
     }
+
+    public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
+        return onPullDistance(deltaDistance, displacement);
+    }
+
+    public void onFlingVelocity(int velocity) { }
+
+    public void onRelease(MotionEvent ev) {
+        onRelease();
+    }
 }
diff --git a/src/com/android/launcher3/util/GridOccupancy.java b/src/com/android/launcher3/util/GridOccupancy.java
index 43e486c..f248e58 100644
--- a/src/com/android/launcher3/util/GridOccupancy.java
+++ b/src/com/android/launcher3/util/GridOccupancy.java
@@ -7,7 +7,7 @@
 /**
  * Utility object to manage the occupancy in a grid.
  */
-public class GridOccupancy extends AbsGridOccupancy {
+public class GridOccupancy {
 
     private final int mCountX;
     private final int mCountY;
@@ -30,7 +30,24 @@
      * @return true if a vacant cell was found
      */
     public boolean findVacantCell(int[] vacantOut, int spanX, int spanY) {
-        return super.findVacantCell(vacantOut, cells, mCountX, mCountY, spanX, spanY);
+        for (int y = 0; (y + spanY) <= mCountY; y++) {
+            for (int x = 0; (x + spanX) <= mCountX; x++) {
+                boolean available = !cells[x][y];
+                out:
+                for (int i = x; i < x + spanX; i++) {
+                    for (int j = y; j < y + spanY; j++) {
+                        available = available && !cells[i][j];
+                        if (!available) break out;
+                    }
+                }
+                if (available) {
+                    vacantOut[0] = x;
+                    vacantOut[1] = y;
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     public void copyTo(GridOccupancy dest) {
diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java
index 1cec0ec..296efe9 100644
--- a/src/com/android/launcher3/util/IOUtils.java
+++ b/src/com/android/launcher3/util/IOUtils.java
@@ -19,7 +19,6 @@
 import android.os.FileUtils;
 import android.util.Log;
 
-import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 
 import java.io.ByteArrayOutputStream;
@@ -51,17 +50,7 @@
     }
 
     public static long copy(InputStream from, OutputStream to) throws IOException {
-        if (Utilities.ATLEAST_Q) {
-            return FileUtils.copy(from, to);
-        }
-        byte[] buf = new byte[BUF_SIZE];
-        long total = 0;
-        int r;
-        while ((r = from.read(buf)) != -1) {
-            to.write(buf, 0, r);
-            total += r;
-        }
-        return total;
+        return FileUtils.copy(from, to);
     }
 
     public static void closeSilently(Closeable c) {
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
index 6128eb4..a207d5c 100644
--- a/src/com/android/launcher3/util/IconSizeSteps.kt
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -49,5 +49,9 @@
 
     companion object {
         internal const val TEXT_STEP = 1
+
+        // This icon extra step is used for stepping down logic in extreme cases when it's
+        // necessary to reduce the icon size below minimum size available in [icon_size_steps].
+        internal const val ICON_SIZE_STEP_EXTRA = 2
     }
 }
diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt
new file mode 100644
index 0000000..ebf4656
--- /dev/null
+++ b/src/com/android/launcher3/util/ItemInflater.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.appwidget.AppWidgetHostView
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.View.OnClickListener
+import android.view.View.OnFocusChangeListener
+import android.view.ViewGroup
+import com.android.launcher3.BubbleTextView
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.R
+import com.android.launcher3.apppairs.AppPairIcon
+import com.android.launcher3.folder.FolderIcon
+import com.android.launcher3.model.ModelWriter
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemFactory
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.widget.LauncherWidgetHolder
+import com.android.launcher3.widget.PendingAppWidgetHostView
+import com.android.launcher3.widget.WidgetInflater
+
+/** Utility class to inflate View for a model item */
+class ItemInflater<T>(
+    private val context: T,
+    private val widgetHolder: LauncherWidgetHolder,
+    private val clickListener: OnClickListener,
+    private val focusListener: OnFocusChangeListener,
+    private val defaultParent: ViewGroup
+) where T : Context, T : ActivityContext {
+
+    private val widgetInflater = WidgetInflater(context)
+
+    @JvmOverloads
+    fun inflateItem(item: ItemInfo, writer: ModelWriter, nullableParent: ViewGroup? = null): View? {
+        val parent = nullableParent ?: defaultParent
+        when (item.itemType) {
+            Favorites.ITEM_TYPE_APPLICATION,
+            Favorites.ITEM_TYPE_DEEP_SHORTCUT,
+            Favorites.ITEM_TYPE_SEARCH_ACTION -> {
+                var info =
+                    if (item is WorkspaceItemFactory) {
+                        (item as WorkspaceItemFactory).makeWorkspaceItem(context)
+                    } else {
+                        item as WorkspaceItemInfo
+                    }
+                if (info.container == Favorites.CONTAINER_PREDICTION) {
+                    // Came from all apps prediction row -- make a copy
+                    info = WorkspaceItemInfo(info)
+                }
+                return createShortcut(info, parent)
+            }
+            Favorites.ITEM_TYPE_FOLDER ->
+                return FolderIcon.inflateFolderAndIcon(
+                    R.layout.folder_icon,
+                    context,
+                    parent,
+                    item as FolderInfo
+                )
+            Favorites.ITEM_TYPE_APP_PAIR ->
+                return AppPairIcon.inflateIcon(
+                    R.layout.app_pair_icon,
+                    context,
+                    parent,
+                    item as AppPairInfo,
+                    BubbleTextView.DISPLAY_WORKSPACE
+                )
+            Favorites.ITEM_TYPE_APPWIDGET,
+            Favorites.ITEM_TYPE_CUSTOM_APPWIDGET ->
+                return inflateAppWidget(item as LauncherAppWidgetInfo, writer)
+            else -> throw RuntimeException("Invalid Item Type")
+        }
+    }
+
+    /**
+     * Creates a view representing a shortcut inflated from the specified resource.
+     *
+     * @param parent The group the shortcut belongs to. This is not necessarily the group where the
+     *   shortcut should be added.
+     * @param info The data structure describing the shortcut.
+     * @return A View inflated from layoutResId.
+     */
+    private fun createShortcut(info: WorkspaceItemInfo, parent: ViewGroup): View {
+        val favorite =
+            LayoutInflater.from(parent.context).inflate(R.layout.app_icon, parent, false)
+                as BubbleTextView
+        favorite.applyFromWorkspaceItem(info)
+        favorite.setOnClickListener(clickListener)
+        favorite.onFocusChangeListener = focusListener
+        return favorite
+    }
+
+    private fun inflateAppWidget(item: LauncherAppWidgetInfo, writer: ModelWriter): View? {
+        TraceHelper.INSTANCE.beginSection("BIND_WIDGET_id=" + item.appWidgetId)
+        try {
+            val (type, reason, _, isUpdate, widgetInfo) = widgetInflater.inflateAppWidget(item)
+            if (type == WidgetInflater.TYPE_DELETE) {
+                writer.deleteItemFromDatabase(item, reason)
+                return null
+            }
+            if (isUpdate) {
+                writer.updateItemInDatabase(item)
+            }
+            val view =
+                if (type == WidgetInflater.TYPE_PENDING || widgetInfo == null)
+                    PendingAppWidgetHostView(context, widgetHolder, item, widgetInfo)
+                else widgetHolder.createView(item.appWidgetId, widgetInfo)
+            prepareAppWidget(view, item)
+            return view
+        } finally {
+            TraceHelper.INSTANCE.endSection()
+        }
+    }
+
+    fun prepareAppWidget(hostView: AppWidgetHostView, item: LauncherAppWidgetInfo) {
+        hostView.tag = item
+        hostView.isFocusable = true
+        hostView.onFocusChangeListener = focusListener
+    }
+}
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index b6af314..063313a 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -65,7 +65,7 @@
      * Returns a matcher for items within folders.
      */
     public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
-        return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+        return info -> info instanceof FolderInfo && ((FolderInfo) info).getContents().stream()
                 .anyMatch(childOperator);
     }
 
diff --git a/src/com/android/launcher3/util/KeyboardShortcutsDelegate.java b/src/com/android/launcher3/util/KeyboardShortcutsDelegate.java
index c9db83d..e4e0bae 100644
--- a/src/com/android/launcher3/util/KeyboardShortcutsDelegate.java
+++ b/src/com/android/launcher3/util/KeyboardShortcutsDelegate.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
 
 import android.util.Log;
@@ -27,6 +28,7 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
@@ -118,17 +120,22 @@
                 return true;
             } else if (mLauncher.getAppsView().isInAllApps()) {
                 // Close all apps if there are no open floating views.
-                closeAllApps();
+                mLauncher.getStateManager().goToState(NORMAL, true);
+                return true;
+            } else if (mLauncher.isInState(LauncherState.OVERVIEW)
+                    || mLauncher.isInState(LauncherState.OVERVIEW_SPLIT_SELECT)) {
+                // Close Overview and return to home.
+                mLauncher.getStateManager().goToState(NORMAL, true);
+                return true;
+            } else if (mLauncher.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
+                // Return to the previous state (Overview) when the modal task is open.
+                mLauncher.getStateManager().goToState(OVERVIEW, true);
                 return true;
             }
         }
         return null;
     }
 
-    private void closeAllApps() {
-        mLauncher.getStateManager().goToState(NORMAL, true);
-    }
-
     /**
      * Handle key up event.
      * @param keyCode code of the key being pressed.
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index f73940b..02779ce 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -19,9 +19,11 @@
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -58,6 +60,8 @@
                                 : null);
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 ((FolderIcon) v).updatePreviewItems(updates::contains);
+            } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
+                appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
             }
 
             // Iterate all items
@@ -86,6 +90,8 @@
                 ((PendingAppWidgetHostView) v).applyState();
             } else if (v instanceof FolderIcon && info instanceof FolderInfo) {
                 ((FolderIcon) v).updatePreviewItems(updates::contains);
+            } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
+                appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
             }
             // process all the shortcuts
             return false;
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index e5bbcb1..d59c339 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -65,4 +65,9 @@
      * When turned on, we enable AGA related session summary logging.
      */
     public static final String AGA_SESSION_SUMMARY_LOG = "AGASessionSummaryLog";
+
+    /**
+     * When turned on, we enable long press nav handle related logging.
+     */
+    public static final String NAV_HANDLE_LONG_PRESS = "NavHandleLongPress";
 }
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index b966d8e..1a0f9a0 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -28,17 +28,15 @@
 import com.android.launcher3.util.ResourceBasedOverride.Overrides;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
 
 /**
  * Utility class for defining singletons which are initiated on main thread.
  */
-public class MainThreadInitializedObject<T> {
+public class MainThreadInitializedObject<T extends SafeCloseable> {
 
     private final ObjectProvider<T> mProvider;
     private T mValue;
@@ -48,14 +46,14 @@
     }
 
     public T get(Context context) {
-        if (context instanceof SandboxContext sc) {
+        Context app = context.getApplicationContext();
+        if (app instanceof SandboxApplication sc) {
             return sc.getObject(this);
         }
 
         if (mValue == null) {
             if (Looper.myLooper() == Looper.getMainLooper()) {
-                mValue = TraceHelper.allowIpcs("main.thread.object",
-                        () -> mProvider.get(context.getApplicationContext()));
+                mValue = TraceHelper.allowIpcs("main.thread.object", () -> mProvider.get(app));
             } else {
                 try {
                     return MAIN_EXECUTOR.submit(() -> get(context)).get();
@@ -67,8 +65,18 @@
         return mValue;
     }
 
-    public T getNoCreate() {
-        return mValue;
+    /**
+     * Executes the callback is the value is already created
+     * @return true if the callback was executed, false otherwise
+     */
+    public boolean executeIfCreated(Consumer<T> callback) {
+        T v = mValue;
+        if (v != null) {
+            callback.accept(v);
+            return true;
+        } else {
+            return false;
+        }
     }
 
     @VisibleForTesting
@@ -79,8 +87,8 @@
     /**
      * Initializes a provider based on resource overrides
      */
-    public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride(
-            Class<T> clazz, int resourceId) {
+    public static <T extends ResourceBasedOverride & SafeCloseable> MainThreadInitializedObject<T>
+            forOverride(Class<T> clazz, int resourceId) {
         return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId));
     }
 
@@ -89,24 +97,36 @@
         T get(Context context);
     }
 
+    public interface SandboxApplication {
+
+        /**
+         * Find a cached object from mObjectMap if we have already created one. If not, generate
+         * an object using the provider.
+         */
+        <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object);
+
+        @UiThread
+        default <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
+            return object.mProvider.get((Context) this);
+        }
+    }
+
     /**
      * Abstract Context which allows custom implementations for
      * {@link MainThreadInitializedObject} providers
      */
-    public static class SandboxContext extends ContextWrapper {
+    public static class SandboxContext extends ContextWrapper implements SandboxApplication {
 
         private static final String TAG = "SandboxContext";
 
-        protected final Set<MainThreadInitializedObject> mAllowedObjects;
-        protected final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
-        protected final ArrayList<Object> mOrderedObjects = new ArrayList<>();
+        private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
+        private final ArrayList<SafeCloseable> mOrderedObjects = new ArrayList<>();
 
         private final Object mDestroyLock = new Object();
         private boolean mDestroyed = false;
 
-        public SandboxContext(Context base, MainThreadInitializedObject... allowedObjects) {
+        public SandboxContext(Context base) {
             super(base);
-            mAllowedObjects = new HashSet<>(Arrays.asList(allowedObjects));
         }
 
         @Override
@@ -118,20 +138,14 @@
             synchronized (mDestroyLock) {
                 // Destroy in reverse order
                 for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
-                    Object o = mOrderedObjects.get(i);
-                    if (o instanceof SafeCloseable) {
-                        ((SafeCloseable) o).close();
-                    }
+                    mOrderedObjects.get(i).close();
                 }
                 mDestroyed = true;
             }
         }
 
-        /**
-         * Find a cached object from mObjectMap if we have already created one. If not, generate
-         * an object using the provider.
-         */
-        protected <T> T getObject(MainThreadInitializedObject<T> object) {
+        @Override
+        public <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object) {
             synchronized (mDestroyLock) {
                 if (mDestroyed) {
                     Log.e(TAG, "Static object access with a destroyed context");
@@ -142,12 +156,6 @@
                 }
                 if (Looper.myLooper() == Looper.getMainLooper()) {
                     t = createObject(object);
-                    // Check if we've explicitly allowed the object or if it's a SafeCloseable,
-                    // it will get destroyed in onDestroy()
-                    if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
-                        throw new IllegalStateException("Leaking unknown objects "
-                                + object + "  " + object.mProvider + " " + t);
-                    }
                     mObjectMap.put(object, t);
                     mOrderedObjects.add(t);
                     return t;
@@ -161,17 +169,12 @@
             }
         }
 
-        @UiThread
-        protected <T> T createObject(MainThreadInitializedObject<T> object) {
-            return object.mProvider.get(this);
-        }
-
         /**
          * Put a value into mObjectMap, can be used to put mocked MainThreadInitializedObject
          * instances into SandboxContext.
          */
-        @VisibleForTesting
-        public <T> void putObject(MainThreadInitializedObject<T> object, T value) {
+        public <T extends SafeCloseable> void putObject(
+                MainThreadInitializedObject<T> object, T value) {
             mObjectMap.put(object, value);
         }
     }
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.kt b/src/com/android/launcher3/util/OnboardingPrefs.kt
index 4528cba..370b4c8 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.kt
+++ b/src/com/android/launcher3/util/OnboardingPrefs.kt
@@ -75,4 +75,8 @@
 
     @JvmField
     val HOTSEAT_LONGPRESS_TIP_SEEN = backedUpItem("launcher.hotseat_longpress_tip_seen", false)
+
+    @JvmField
+    val TASKBAR_CIRCLE_TO_SEARCH_EDU_SEEN =
+        backedUpItem("launcher.taskbar_circle_to_search_edu_seen", false)
 }
diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java
index 2ef1e1f..d09d801 100644
--- a/src/com/android/launcher3/util/OverlayEdgeEffect.java
+++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java
@@ -17,10 +17,13 @@
 
 import android.content.Context;
 import android.graphics.Canvas;
+import android.os.SystemClock;
+import android.view.MotionEvent;
 import android.widget.EdgeEffect;
 
+import com.android.launcher3.BuildConfig;
 import com.android.launcher3.Utilities;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
 
 /**
  * Extension of {@link EdgeEffect} which shows the Launcher overlay
@@ -28,11 +31,11 @@
 public class OverlayEdgeEffect extends EdgeEffectCompat {
 
     protected float mDistance;
-    protected final LauncherOverlay mOverlay;
+    protected final LauncherOverlayTouchProxy mOverlay;
     protected boolean mIsScrolling;
     protected final boolean mIsRtl;
 
-    public OverlayEdgeEffect(Context context, LauncherOverlay overlay) {
+    public OverlayEdgeEffect(Context context, LauncherOverlayTouchProxy overlay) {
         super(context);
         mOverlay = overlay;
         mIsRtl = Utilities.isRtl(context.getResources());
@@ -44,12 +47,30 @@
     }
 
     public float onPullDistance(float deltaDistance, float displacement) {
+        // Fallback implementation, will never actually get called
+        if (BuildConfig.IS_DEBUG_DEVICE) {
+            throw new RuntimeException("Wrong method called");
+        }
+        MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+                MotionEvent.ACTION_MOVE, displacement, 0, 0);
+        try {
+            return onPullDistance(deltaDistance, displacement, mv);
+        } finally {
+            mv.recycle();
+        }
+    }
+
+    @Override
+    public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
         mDistance = Math.max(0f, deltaDistance + mDistance);
         if (!mIsScrolling) {
-            mOverlay.onScrollInteractionBegin();
+            int originalAction = ev.getAction();
+            ev.setAction(MotionEvent.ACTION_DOWN);
+            mOverlay.onOverlayMotionEvent(ev, 0);
+            ev.setAction(originalAction);
             mIsScrolling = true;
         }
-        mOverlay.onScrollChange(mDistance, mIsRtl);
+        mOverlay.onOverlayMotionEvent(ev, mDistance);
         return mDistance > 0 ? deltaDistance : 0;
     }
 
@@ -63,9 +84,30 @@
 
     @Override
     public void onRelease() {
+        // Fallback implementation, will never actually get called
+        if (BuildConfig.IS_DEBUG_DEVICE) {
+            throw new RuntimeException("Wrong method called");
+        }
+        MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+                MotionEvent.ACTION_UP, mDistance, 0, 0);
+        onRelease(mv);
+        mv.recycle();
+    }
+
+    @Override
+    public void onFlingVelocity(int velocity) {
+        mOverlay.onFlingVelocity(velocity);
+    }
+
+    @Override
+    public void onRelease(MotionEvent ev) {
         if (mIsScrolling) {
+            int originalAction = ev.getAction();
+            ev.setAction(MotionEvent.ACTION_UP);
+            mOverlay.onOverlayMotionEvent(ev, mDistance);
+            ev.setAction(originalAction);
+
             mDistance = 0;
-            mOverlay.onScrollInteractionEnd();
             mIsScrolling = false;
         }
     }
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 91203a7..3684f56 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.util;
 
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -28,8 +30,8 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -38,6 +40,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -47,18 +50,21 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 
-import java.net.URISyntaxException;
 import java.util.List;
 import java.util.Objects;
 
 /**
  * Utility methods using package manager
  */
-public class PackageManagerHelper {
+public class PackageManagerHelper implements SafeCloseable{
 
     private static final String TAG = "PackageManagerHelper";
 
     @NonNull
+    public static final MainThreadInitializedObject<PackageManagerHelper> INSTANCE =
+            new MainThreadInitializedObject<>(PackageManagerHelper::new);
+
+    @NonNull
     private final Context mContext;
 
     @NonNull
@@ -73,6 +79,9 @@
         mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class));
     }
 
+    @Override
+    public void close() { }
+
     /**
      * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
      * guarantee that the app is on SD card.
@@ -104,6 +113,39 @@
     }
 
     /**
+     * Returns whether the target app is archived for a given user
+     */
+    @SuppressWarnings("NewApi")
+    public boolean isAppArchivedForUser(@NonNull final String packageName,
+            @NonNull final UserHandle user) {
+        if (!Flags.enableSupportForArchiving()) {
+            return false;
+        }
+        final ApplicationInfo info = getApplicationInfo(
+                // LauncherApps does not support long flags currently. Since archived apps are
+                // subset of uninstalled apps, this filter also includes archived apps.
+                packageName, user, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+        return info != null && info.isArchived;
+    }
+
+    /**
+     * Returns whether the target app is in archived state
+     */
+    @SuppressWarnings("NewApi")
+    public boolean isAppArchived(@NonNull final String packageName) {
+        final ApplicationInfo info;
+        try {
+            info = mPm.getPackageInfo(packageName,
+                    PackageManager.PackageInfoFlags.of(
+                            PackageManager.MATCH_ARCHIVED_PACKAGES)).applicationInfo;
+            return info.isArchived;
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Failed to get applicationInfo for package: " + packageName, e);
+            return false;
+        }
+    }
+
+    /**
      * Returns the application info for the provided package or null
      */
     @Nullable
@@ -111,17 +153,12 @@
             @NonNull final UserHandle user, final int flags) {
         try {
             ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
-            return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled
-                    ? null : info;
+            return !isPackageInstalledOrArchived(info) || !info.enabled ? null : info;
         } catch (PackageManager.NameNotFoundException e) {
             return null;
         }
     }
 
-    public boolean isSafeMode() {
-        return mPm.isSafeMode();
-    }
-
     @Nullable
     public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) {
         List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
@@ -137,43 +174,15 @@
         return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
     }
 
-    public Intent getMarketIntent(String packageName) {
-        return new Intent(Intent.ACTION_VIEW)
-                .setData(new Uri.Builder()
-                        .scheme("market")
-                        .authority("details")
-                        .appendQueryParameter("id", packageName)
-                        .build())
-                .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app")
-                        .authority(mContext.getPackageName()).build());
-    }
-
-    /**
-     * Creates a new market search intent.
-     */
-    public static Intent getMarketSearchIntent(Context context, String query) {
-        try {
-            Intent intent = Intent.parseUri(context.getString(R.string.market_search_intent), 0);
-            if (!TextUtils.isEmpty(query)) {
-                intent.setData(
-                        intent.getData().buildUpon().appendQueryParameter("q", query).build());
-            }
-            return intent;
-        } catch (URISyntaxException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     /**
      * Starts the details activity for {@code info}
      */
-    public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
-        if (info instanceof ItemInfoWithIcon
-                && (((ItemInfoWithIcon) info).runtimeStatusFlags
-                    & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
-            ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info;
-            mContext.startActivity(new PackageManagerHelper(mContext)
-                    .getMarketIntent(appInfo.getTargetComponent().getPackageName()));
+    public static void startDetailsActivityForInfo(Context context, ItemInfo info,
+            Rect sourceBounds, Bundle opts) {
+        if (info instanceof ItemInfoWithIcon appInfo
+                && (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+            context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent(
+                    appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()));
             return;
         }
         ComponentName componentName = null;
@@ -188,9 +197,10 @@
         }
         if (componentName != null) {
             try {
-                mLauncherApps.startAppDetailsActivity(componentName, info.user, sourceBounds, opts);
+                context.getSystemService(LauncherApps.class).startAppDetailsActivity(componentName,
+                        info.user, sourceBounds, opts);
             } catch (SecurityException | ActivityNotFoundException e) {
-                Toast.makeText(mContext, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+                Toast.makeText(context, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                 Log.e(TAG, "Unable to launch settings", e);
             }
         }
@@ -249,6 +259,7 @@
 
     /**
      * Returns true if Launcher has the permission to access shortcuts.
+     *
      * @see LauncherApps#hasShortcutHostPermission()
      */
     public static boolean hasShortcutsPermission(Context context) {
@@ -267,4 +278,11 @@
         }
         return 100;
     }
+
+    /** Returns true in case app is installed on the device or in archived state. */
+    @SuppressWarnings("NewApi")
+    private boolean isPackageInstalledOrArchived(ApplicationInfo info) {
+        return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || (
+                Flags.enableSupportForArchiving() && info.isArchived);
+    }
 }
diff --git a/src/com/android/launcher3/util/PluginManagerWrapper.java b/src/com/android/launcher3/util/PluginManagerWrapper.java
new file mode 100644
index 0000000..b27aa12
--- /dev/null
+++ b/src/com/android/launcher3/util/PluginManagerWrapper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+
+import com.android.launcher3.R;
+import com.android.systemui.plugins.Plugin;
+import com.android.systemui.plugins.PluginListener;
+
+import java.io.PrintWriter;
+
+public class PluginManagerWrapper implements ResourceBasedOverride, SafeCloseable {
+
+    public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
+            forOverride(PluginManagerWrapper.class, R.string.plugin_manager_wrapper_class);
+
+    public <T extends Plugin> void addPluginListener(
+            PluginListener<T> listener, Class<T> pluginClass) {
+        addPluginListener(listener, pluginClass, false);
+    }
+
+    public <T extends Plugin> void addPluginListener(
+            PluginListener<T> listener, Class<T> pluginClass, boolean allowMultiple) {
+    }
+
+    public void removePluginListener(PluginListener<? extends Plugin> listener) { }
+
+    @Override
+    public void close() { }
+
+    public void dump(PrintWriter pw) { }
+}
diff --git a/src/com/android/launcher3/util/ResourceBasedOverride.java b/src/com/android/launcher3/util/ResourceBasedOverride.java
index e2c4992..36b9cf7 100644
--- a/src/com/android/launcher3/util/ResourceBasedOverride.java
+++ b/src/com/android/launcher3/util/ResourceBasedOverride.java
@@ -34,16 +34,20 @@
         public static <T extends ResourceBasedOverride> T getObject(
                 Class<T> clazz, Context context, int resId) {
             String className = context.getString(resId);
-            if (!TextUtils.isEmpty(className)) {
-                try {
-                    Class<?> cls = Class.forName(className);
-                    return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
-                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
-                        | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+            boolean isOverridden = !TextUtils.isEmpty(className);
+
+            // First try to load the class with "Context" param
+            try {
+                Class<?> cls = isOverridden ? Class.forName(className) : clazz;
+                return (T) cls.getDeclaredConstructor(Context.class).newInstance(context);
+            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
+                     | ClassCastException | NoSuchMethodException | InvocationTargetException e) {
+                if (isOverridden) {
                     Log.e(TAG, "Bad overriden class", e);
                 }
             }
 
+            // Load the base class with no parameter
             try {
                 return clazz.newInstance();
             } catch (InstantiationException|IllegalAccessException e) {
diff --git a/src/com/android/launcher3/util/RunnableList.java b/src/com/android/launcher3/util/RunnableList.java
index f6e0c57..2b8bf56 100644
--- a/src/com/android/launcher3/util/RunnableList.java
+++ b/src/com/android/launcher3/util/RunnableList.java
@@ -69,4 +69,11 @@
             }
         }
     }
+
+    /**
+     * Returns true if the list has been destroyed
+     */
+    public boolean isDestroyed() {
+        return mDestroyed;
+    }
 }
diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java
index 67530a6..e16e477 100644
--- a/src/com/android/launcher3/util/ScreenOnTracker.java
+++ b/src/com/android/launcher3/util/ScreenOnTracker.java
@@ -27,7 +27,7 @@
 /**
  * Utility class for tracking if the screen is currently on or off
  */
-public class ScreenOnTracker {
+public class ScreenOnTracker implements SafeCloseable {
 
     public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
             new MainThreadInitializedObject<>(ScreenOnTracker::new);
@@ -35,14 +35,21 @@
     private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
     private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
 
+    private final Context mContext;
     private boolean mIsScreenOn;
 
     private ScreenOnTracker(Context context) {
         // Assume that the screen is on to begin with
+        mContext = context;
         mIsScreenOn = true;
         mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
     }
 
+    @Override
+    public void close() {
+        mReceiver.unregisterReceiverSafely(mContext);
+    }
+
     private void onReceive(Intent intent) {
         String action = intent.getAction();
         if (ACTION_SCREEN_ON.equals(action)) {
diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java
index 91cf835..07b7941 100644
--- a/src/com/android/launcher3/util/ShortcutUtil.java
+++ b/src/com/android/launcher3/util/ShortcutUtil.java
@@ -15,9 +15,10 @@
  */
 package com.android.launcher3.util;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutKey;
@@ -34,7 +35,7 @@
      * Returns true when we should show depp shortcuts in shortcut menu for the item.
      */
     public static boolean supportsDeepShortcuts(ItemInfo info) {
-        return isActive(info) && isApp(info) && !WidgetsModel.GO_DISABLE_WIDGETS;
+        return isActive(info) && isApp(info) && !!WIDGETS_ENABLED;
     }
 
     /**
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index f4a0225..837d7bc 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -169,6 +169,15 @@
             dividerWidthPercent = visualDividerBounds.width() / totalWidth;
             dividerHeightPercent = visualDividerBounds.height() / totalHeight;
         }
+
+        @Override
+        public String toString() {
+            return "LeftTop: " + leftTopBounds + ", taskId: " + leftTopTaskId + "\n"
+                    + "RightBottom: " + rightBottomBounds + ", taskId: " + rightBottomTaskId +  "\n"
+                    + "Divider: " + visualDividerBounds + "\n"
+                    + "AppsVertical? " + appsStackedVertically + "\n"
+                    + "snapPosition: " + snapPosition;
+        }
     }
 
     public static class SplitStageInfo {
diff --git a/src/com/android/launcher3/util/StartActivityParams.java b/src/com/android/launcher3/util/StartActivityParams.java
index b48562f..d66b0a0 100644
--- a/src/com/android/launcher3/util/StartActivityParams.java
+++ b/src/com/android/launcher3/util/StartActivityParams.java
@@ -52,6 +52,7 @@
     public int flagsValues;
     public int extraFlags;
     public Bundle options;
+    public boolean requireActivityResult = true;
 
     public StartActivityParams(Activity activity, int requestCode) {
         this(activity.createPendingResult(requestCode, new Intent(),
@@ -74,6 +75,7 @@
         flagsValues = parcel.readInt();
         extraFlags = parcel.readInt();
         options = parcel.readBundle();
+        requireActivityResult = parcel.readInt() != 0;
     }
 
 
@@ -94,6 +96,7 @@
         parcel.writeInt(flagsValues);
         parcel.writeInt(extraFlags);
         parcel.writeBundle(options);
+        parcel.writeInt(requireActivityResult ? 1 : 0);
     }
 
     /** Perform the operation on the pendingIntent. */
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index 138cc4a..edcd3f6 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -20,12 +20,10 @@
 
 import androidx.annotation.MainThread;
 
-import com.android.launcher3.Utilities;
+import kotlin.random.Random;
 
 import java.util.function.Supplier;
 
-import kotlin.random.Random;
-
 /**
  * A wrapper around {@link Trace} to allow better testing.
  *
@@ -67,9 +65,6 @@
     @SuppressWarnings("NewApi")
     @SuppressLint("NewApi")
     public SafeCloseable beginAsyncSection(String sectionName) {
-        if (!Utilities.ATLEAST_Q) {
-            return () -> { };
-        }
         int cookie = Random.Default.nextInt();
         Trace.beginAsyncSection(sectionName, cookie);
         return () -> Trace.endAsyncSection(sectionName, cookie);
@@ -81,9 +76,6 @@
     @SuppressWarnings("NewApi")
     @SuppressLint("NewApi")
     public SafeCloseable allowIpcs(String rpcName) {
-        if (!Utilities.ATLEAST_Q) {
-            return () -> { };
-        }
         int cookie = Random.Default.nextInt();
         Trace.beginAsyncSection(rpcName, cookie);
         return () -> Trace.endAsyncSection(rpcName, cookie);
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index 4f20bbc..b2b4959 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -19,21 +19,14 @@
 import static android.os.VibrationEffect.createPredefined;
 import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
 
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.media.AudioAttributes;
-import android.os.Build;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -41,15 +34,12 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
 
 /**
  * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
  */
-@TargetApi(Build.VERSION_CODES.Q)
-public class VibratorWrapper {
+public class VibratorWrapper implements SafeCloseable {
 
     public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
             new MainThreadInitializedObject<>(VibratorWrapper::new);
@@ -75,9 +65,6 @@
     @Nullable
     private final VibrationEffect mBumpEffect;
 
-    @Nullable
-    private final VibrationEffect mSearchEffect;
-
     private long mLastDragTime;
     private final int mThresholdUntilNextDragCallMillis;
 
@@ -90,6 +77,7 @@
     private final Vibrator mVibrator;
     private final boolean mHasVibrator;
 
+    private ContentObserver mHapticFeedbackObserver;
     private boolean mIsHapticFeedbackEnabled;
 
     private VibratorWrapper(Context context) {
@@ -99,14 +87,14 @@
         if (mHasVibrator) {
             final ContentResolver resolver = context.getContentResolver();
             mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
-            final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+            mHapticFeedbackObserver = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
                 @Override
                 public void onChange(boolean selfChange) {
                     mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
                 }
             };
             resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
-                    false /* notifyForDescendants */, observer);
+                    false /* notifyForDescendants */, mHapticFeedbackObserver);
         } else {
             mIsHapticFeedbackEnabled = false;
         }
@@ -137,24 +125,12 @@
             mBumpEffect = null;
             mThresholdUntilNextDragCallMillis = 0;
         }
+    }
 
-        if (Utilities.ATLEAST_R && mVibrator.areAllPrimitivesSupported(
-                VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
-                VibrationEffect.Composition.PRIMITIVE_TICK)) {
-            if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get()) {
-                mSearchEffect = VibrationEffect.startComposition()
-                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1f)
-                        .compose();
-            } else {
-                // quiet ramp, short pause, then sharp tick
-                mSearchEffect = VibrationEffect.startComposition()
-                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 0.25f)
-                        .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1f, 50)
-                        .compose();
-            }
-        } else {
-            // fallback for devices without composition support
-            mSearchEffect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK);
+    @Override
+    public void close() {
+        if (mHapticFeedbackObserver != null) {
+            mContext.getContentResolver().unregisterContentObserver(mHapticFeedbackObserver);
         }
     }
 
@@ -226,8 +202,7 @@
     public void vibrate(int primitiveId, float primitiveScale, VibrationEffect fallbackEffect) {
         if (mHasVibrator && mIsHapticFeedbackEnabled) {
             UI_HELPER_EXECUTOR.execute(() -> {
-                if (Utilities.ATLEAST_R && primitiveId >= 0
-                        && mVibrator.areAllPrimitivesSupported(primitiveId)) {
+                if (primitiveId >= 0 && mVibrator.areAllPrimitivesSupported(primitiveId)) {
                     mVibrator.vibrate(VibrationEffect.startComposition()
                             .addPrimitive(primitiveId, primitiveScale)
                             .compose(), VIBRATION_ATTRS);
@@ -238,13 +213,6 @@
         }
     }
 
-    /** Indicates that search has been invoked. */
-    public void vibrateForSearch() {
-        if (mSearchEffect != null) {
-            vibrate(mSearchEffect);
-        }
-    }
-
     /** Indicates that Taskbar has been invoked. */
     public void vibrateForTaskbarUnstash() {
         if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
@@ -256,38 +224,4 @@
             vibrate(primitiveLowTickEffect);
         }
     }
-
-    /** Indicates that search will be invoked if the current gesture is maintained. */
-    public void vibrateForSearchHint() {
-        if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get() && Utilities.ATLEAST_S
-                && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
-            LauncherPrefs launcherPrefs = LauncherPrefs.get(mContext);
-            float startScale = launcherPrefs.get(
-                    LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT) / 100f;
-            float endScale = launcherPrefs.get(
-                    LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT) / 100f;
-            int scaleExponent = launcherPrefs.get(
-                    LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT);
-            int iterations = launcherPrefs.get(
-                    LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS);
-            int delayMs = launcherPrefs.get(
-                    LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY);
-
-            VibrationEffect.Composition composition = VibrationEffect.startComposition();
-            for (int i = 0; i < iterations; i++) {
-                float t = i / (iterations - 1f);
-                float scale = (float) Math.pow((1 - t) * startScale + t * endScale,
-                        scaleExponent);
-                if (i == 0) {
-                    // Adds a delay before the ramp starts
-                    composition.addPrimitive(PRIMITIVE_LOW_TICK, scale,
-                            delayMs);
-                } else {
-                    composition.addPrimitive(PRIMITIVE_LOW_TICK, scale);
-                }
-            }
-
-            vibrate(composition.compose());
-        }
-    }
 }
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index fada4a3..26bfd36 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -20,6 +20,8 @@
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewTreeObserver.OnDrawListener;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.Launcher;
 
 import java.util.function.Consumer;
@@ -31,26 +33,23 @@
         OnAttachStateChangeListener {
 
     private final RunnableList mTasks;
-
-    private Consumer<ViewOnDrawExecutor> mOnClearCallback;
+    private final Consumer<ViewOnDrawExecutor> mOnClearCallback;
     private View mAttachedView;
     private boolean mCompleted;
 
-    private boolean mLoadAnimationCompleted;
     private boolean mFirstDrawCompleted;
 
     private boolean mCancelled;
 
-    public ViewOnDrawExecutor(RunnableList tasks) {
+    public ViewOnDrawExecutor(RunnableList tasks,
+            @NonNull Consumer<ViewOnDrawExecutor> onClearCallback) {
         mTasks = tasks;
+        mOnClearCallback = onClearCallback;
     }
 
     public void attachTo(Launcher launcher) {
-        mOnClearCallback = launcher::clearPendingExecutor;
         mAttachedView = launcher.getWorkspace();
-
         mAttachedView.addOnAttachStateChangeListener(this);
-
         if (mAttachedView.isAttachedToWindow()) {
             attachObserver();
         }
@@ -77,17 +76,10 @@
         mAttachedView.post(this);
     }
 
-    public void onLoadAnimationCompleted() {
-        mLoadAnimationCompleted = true;
-        if (mAttachedView != null) {
-            mAttachedView.post(this);
-        }
-    }
-
     @Override
     public void run() {
-        // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
-        if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
+        // Post the pending tasks after first draw
+        if (mFirstDrawCompleted && !mCompleted) {
             markCompleted();
         }
     }
@@ -104,9 +96,8 @@
             mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
             mAttachedView.removeOnAttachStateChangeListener(this);
         }
-        if (mOnClearCallback != null) {
-            mOnClearCallback.accept(this);
-        }
+
+        mOnClearCallback.accept(this);
     }
 
     public void cancel() {
diff --git a/src/com/android/launcher3/util/window/CachedDisplayInfo.java b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
index 23f37aa..c5084ad 100644
--- a/src/com/android/launcher3/util/window/CachedDisplayInfo.java
+++ b/src/com/android/launcher3/util/window/CachedDisplayInfo.java
@@ -16,13 +16,16 @@
 package com.android.launcher3.util.window;
 
 import static com.android.launcher3.util.RotationUtils.deltaRotation;
-import static com.android.launcher3.util.RotationUtils.rotateRect;
 import static com.android.launcher3.util.RotationUtils.rotateSize;
 
+import android.graphics.Insets;
 import android.graphics.Point;
-import android.graphics.Rect;
+import android.view.DisplayCutout;
 import android.view.Surface;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import java.util.Objects;
 
 /**
@@ -30,36 +33,40 @@
  */
 public class CachedDisplayInfo {
 
+    private static final DisplayCutout NO_CUTOUT =
+            new DisplayCutout(Insets.NONE, null, null, null, null);
+
     public final Point size;
     public final int rotation;
-    public final Rect cutout;
+    @NonNull
+    public final DisplayCutout cutout;
 
     public CachedDisplayInfo() {
         this(new Point(0, 0), 0);
     }
 
     public CachedDisplayInfo(Point size, int rotation) {
-        this(size, rotation, new Rect());
+        this(size, rotation, NO_CUTOUT);
     }
 
-    public CachedDisplayInfo(Point size, int rotation, Rect cutout) {
+    public CachedDisplayInfo(Point size, int rotation, @Nullable DisplayCutout cutout) {
         this.size = size;
         this.rotation = rotation;
-        this.cutout = cutout;
+        this.cutout = cutout == null ? NO_CUTOUT : cutout;
     }
 
     /**
      * Returns a CachedDisplayInfo where the properties are normalized to {@link Surface#ROTATION_0}
      */
-    public CachedDisplayInfo normalize() {
+    public CachedDisplayInfo normalize(WindowManagerProxy windowManagerProxy) {
         if (rotation == Surface.ROTATION_0) {
             return this;
         }
         Point newSize = new Point(size);
         rotateSize(newSize, deltaRotation(rotation, Surface.ROTATION_0));
 
-        Rect newCutout = new Rect(cutout);
-        rotateRect(newCutout, deltaRotation(rotation, Surface.ROTATION_0));
+        DisplayCutout newCutout = windowManagerProxy.rotateCutout(
+                cutout, size.x, size.y, rotation, Surface.ROTATION_0);
         return new CachedDisplayInfo(newSize, Surface.ROTATION_0, newCutout);
     }
 
@@ -79,11 +86,16 @@
         CachedDisplayInfo that = (CachedDisplayInfo) o;
         return rotation == that.rotation
                 && Objects.equals(size, that.size)
-                && Objects.equals(cutout, that.cutout);
+                && cutout.getSafeInsetLeft() == that.cutout.getSafeInsetLeft()
+                && cutout.getSafeInsetTop() == that.cutout.getSafeInsetTop()
+                && cutout.getSafeInsetRight() == that.cutout.getSafeInsetRight()
+                && cutout.getSafeInsetBottom() == that.cutout.getSafeInsetBottom();
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(size, rotation, cutout);
+        return Objects.hash(size, rotation,
+                cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
+                cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
     }
 }
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 51a96c4..4b004f3 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -17,6 +17,7 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.launcher3.Utilities.dpToPx;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
 import static com.android.launcher3.testing.shared.ResourceUtils.NAVBAR_HEIGHT;
@@ -49,12 +50,16 @@
 import android.view.WindowManager;
 import android.view.WindowMetrics;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.WindowBounds;
 
 import java.util.ArrayList;
@@ -63,7 +68,7 @@
 /**
  * Utility class for mocking some window manager behaviours
  */
-public class WindowManagerProxy implements ResourceBasedOverride {
+public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
 
     private static final String TAG = "WindowManagerProxy";
     public static final int MIN_TABLET_WIDTH = 600;
@@ -90,12 +95,19 @@
     }
 
     /**
+     * Returns true if taskbar is drawn in process
+     */
+    public boolean isTaskbarDrawnInProcess() {
+        return mTaskbarDrawnInProcess;
+    }
+
+    /**
      * Returns a map of normalized info of internal displays to estimated window bounds
      * for that display
      */
     public ArrayMap<CachedDisplayInfo, List<WindowBounds>> estimateInternalDisplayBounds(
             Context displayInfoContext) {
-        CachedDisplayInfo info = getDisplayInfo(displayInfoContext).normalize();
+        CachedDisplayInfo info = getDisplayInfo(displayInfoContext).normalize(this);
         List<WindowBounds> bounds = estimateWindowBounds(displayInfoContext, info);
         ArrayMap<CachedDisplayInfo, List<WindowBounds>> result = new ArrayMap<>();
         result.put(info, bounds);
@@ -105,24 +117,7 @@
     /**
      * Returns the real bounds for the provided display after applying any insets normalization
      */
-    @TargetApi(Build.VERSION_CODES.R)
     public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) {
-        if (!Utilities.ATLEAST_R) {
-            Point smallestSize = new Point();
-            Point largestSize = new Point();
-            getDisplay(displayInfoContext).getCurrentSizeRange(smallestSize, largestSize);
-
-            if (info.size.y > info.size.x) {
-                // Portrait
-                return new WindowBounds(info.size.x, info.size.y, smallestSize.x, largestSize.y,
-                        info.rotation);
-            } else {
-                // Landscape
-                return new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
-                        info.rotation);
-            }
-        }
-
         WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics();
         Rect insets = new Rect();
@@ -133,10 +128,9 @@
     /**
      * Returns an updated insets, accounting for various Launcher UI specific overrides like taskbar
      */
-    @TargetApi(Build.VERSION_CODES.R)
     public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
             Rect outInsets) {
-        if (!Utilities.ATLEAST_R || !mTaskbarDrawnInProcess) {
+        if (!mTaskbarDrawnInProcess) {
             outInsets.set(oldInsets.getSystemWindowInsetLeft(), oldInsets.getSystemWindowInsetTop(),
                     oldInsets.getSystemWindowInsetRight(), oldInsets.getSystemWindowInsetBottom());
             return oldInsets;
@@ -148,18 +142,29 @@
         Resources systemRes = context.getResources();
         Configuration config = systemRes.getConfiguration();
 
-        boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
+        boolean isLargeScreen = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
         boolean isGesture = isGestureNav(context);
         boolean isPortrait = config.screenHeightDp > config.screenWidthDp;
 
-        int bottomNav = isTablet
+        int bottomNav = isLargeScreen
                 ? 0
                 : (isPortrait
                         ? getDimenByName(systemRes, NAVBAR_HEIGHT)
                         : (isGesture
                                 ? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE)
                                 : 0));
-        Insets newNavInsets = Insets.of(navInsets.left, navInsets.top, navInsets.right, bottomNav);
+        int leftNav = navInsets.left;
+        int rightNav = navInsets.right;
+        if (!isLargeScreen && !isGesture && !isPortrait) {
+            // In 3-button landscape/seascape, Launcher should always have nav insets regardless if
+            // it's initiated from fullscreen apps.
+            int navBarWidth = getDimenByName(systemRes, NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
+            switch (getRotation(context)) {
+                case Surface.ROTATION_90 -> rightNav = navBarWidth;
+                case Surface.ROTATION_270 -> leftNav = navBarWidth;
+            }
+        }
+        Insets newNavInsets = Insets.of(leftNav, navInsets.top, rightNav, bottomNav);
         insetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
         insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
 
@@ -183,6 +188,9 @@
             insetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
         }
 
+        applyDisplayCutoutBottomInsetOverrideOnLargeScreen(
+                context, isLargeScreen, dpToPx(config.screenWidthDp), oldInsets, insetsBuilder);
+
         WindowInsets result = insetsBuilder.build();
         Insets systemWindowInsets = result.getInsetsIgnoringVisibility(
                 WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
@@ -191,6 +199,71 @@
         return result;
     }
 
+    /**
+     * For large screen, when display cutout is at bottom left/right corner of screen, override
+     * display cutout's bottom inset to 0, because launcher allows drawing content over that area.
+     */
+    private static void applyDisplayCutoutBottomInsetOverrideOnLargeScreen(
+            @NonNull Context context,
+            boolean isLargeScreen,
+            int screenWidthPx,
+            @NonNull WindowInsets windowInsets,
+            @NonNull WindowInsets.Builder insetsBuilder) {
+        if (!isLargeScreen || !Utilities.ATLEAST_S) {
+            return;
+        }
+
+        final DisplayCutout displayCutout = windowInsets.getDisplayCutout();
+        if (displayCutout == null) {
+            return;
+        }
+
+        if (!areBottomDisplayCutoutsSmallAndAtCorners(
+                displayCutout.getBoundingRectBottom(), screenWidthPx, context.getResources())) {
+            return;
+        }
+
+        Insets oldDisplayCutoutInset = windowInsets.getInsets(WindowInsets.Type.displayCutout());
+        Insets newDisplayCutoutInset = Insets.of(
+                oldDisplayCutoutInset.left,
+                oldDisplayCutoutInset.top,
+                oldDisplayCutoutInset.right,
+                0);
+        insetsBuilder.setInsetsIgnoringVisibility(
+                WindowInsets.Type.displayCutout(), newDisplayCutoutInset);
+    }
+
+    /**
+     * @see doc at {@link #areBottomDisplayCutoutsSmallAndAtCorners(Rect, int, int)}
+     */
+    private static boolean areBottomDisplayCutoutsSmallAndAtCorners(
+            @NonNull Rect cutoutRectBottom, int screenWidthPx, @NonNull Resources res) {
+        return areBottomDisplayCutoutsSmallAndAtCorners(cutoutRectBottom, screenWidthPx,
+                res.getDimensionPixelSize(R.dimen.max_width_and_height_of_small_display_cutout));
+    }
+
+    /**
+     * Return true if bottom display cutouts are at bottom left/right corners, AND has width or
+     * height <= maxWidthAndHeightOfSmallCutoutPx. Note that display cutout rect and screenWidthPx
+     * passed to this method should be in the SAME screen rotation.
+     *
+     * @param cutoutRectBottom bottom display cutout rect, this is based on current screen rotation
+     * @param screenWidthPx screen width in px based on current screen rotation
+     * @param maxWidthAndHeightOfSmallCutoutPx maximum width and height pixels of cutout.
+     */
+    @VisibleForTesting
+    static boolean areBottomDisplayCutoutsSmallAndAtCorners(
+            @NonNull Rect cutoutRectBottom, int screenWidthPx,
+            int maxWidthAndHeightOfSmallCutoutPx) {
+        // Empty cutoutRectBottom means there is no display cutout at the bottom. We should ignore
+        // it by returning false.
+        if (cutoutRectBottom.isEmpty()) {
+            return false;
+        }
+        return (cutoutRectBottom.right <= maxWidthAndHeightOfSmallCutoutPx)
+                || cutoutRectBottom.left >= (screenWidthPx - maxWidthAndHeightOfSmallCutoutPx);
+    }
+
     protected int getStatusBarHeight(Context context, boolean isPortrait, int statusBarInset) {
         Resources systemRes = context.getResources();
         int statusBarHeight = getDimenByName(systemRes,
@@ -204,10 +277,9 @@
      * Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations
      */
     protected List<WindowBounds> estimateWindowBounds(Context context,
-            CachedDisplayInfo displayInfo) {
+            final CachedDisplayInfo displayInfo) {
         int densityDpi = context.getResources().getConfiguration().densityDpi;
-        int rotation = displayInfo.rotation;
-        Rect safeCutout = displayInfo.cutout;
+        final int rotation = displayInfo.rotation;
 
         int minSize = Math.min(displayInfo.size.x, displayInfo.size.y);
         int swDp = (int) dpiFromPx(minSize, densityDpi);
@@ -220,8 +292,7 @@
         }
 
         boolean isTablet = swDp >= MIN_TABLET_WIDTH;
-        boolean isTabletOrGesture = isTablet
-                || (Utilities.ATLEAST_R && isGestureNav(context));
+        boolean isTabletOrGesture = isTablet || isGestureNav(context);
 
         // Use the status bar height resources because current system API to get the status bar
         // height doesn't allow to do this for an arbitrary display, it returns value only
@@ -235,12 +306,12 @@
 
         navBarHeightPortrait = isTablet
                 ? (mTaskbarDrawnInProcess
-                        ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+                        ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
                 : getDimenByName(systemRes, NAVBAR_HEIGHT);
 
         navBarHeightLandscape = isTablet
                 ? (mTaskbarDrawnInProcess
-                        ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+                        ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
                 : (isTabletOrGesture
                         ? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
         navbarWidthLandscape = isTabletOrGesture
@@ -266,8 +337,15 @@
                 statusBarHeight = statusBarHeightLandscape;
             }
 
-            Rect insets = new Rect(safeCutout);
-            rotateRect(insets, rotationChange);
+            DisplayCutout rotatedCutout = rotateCutout(
+                    displayInfo.cutout, displayInfo.size.x, displayInfo.size.y, rotation, i);
+            Rect insets = getSafeInsets(rotatedCutout);
+            if (areBottomDisplayCutoutsSmallAndAtCorners(
+                    rotatedCutout.getBoundingRectBottom(),
+                    bounds.width(),
+                    context.getResources())) {
+                insets.bottom = 0;
+            }
             insets.top = Math.max(insets.top, statusBarHeight);
             insets.bottom = Math.max(insets.bottom, navBarHeight);
 
@@ -317,8 +395,7 @@
             Point size = new Point();
             Display display = getDisplay(displayInfoContext);
             display.getRealSize(size);
-            Rect cutoutRect = new Rect();
-            return new CachedDisplayInfo(size, rotation, cutoutRect);
+            return new CachedDisplayInfo(size, rotation);
         }
     }
 
@@ -328,13 +405,8 @@
     @TargetApi(Build.VERSION_CODES.S)
     protected CachedDisplayInfo getDisplayInfo(WindowMetrics windowMetrics, int rotation) {
         Point size = new Point(windowMetrics.getBounds().right, windowMetrics.getBounds().bottom);
-        Rect cutoutRect = new Rect();
-        DisplayCutout cutout = windowMetrics.getWindowInsets().getDisplayCutout();
-        if (cutout != null) {
-            cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
-                    cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
-        }
-        return new CachedDisplayInfo(size, rotation, cutoutRect);
+        return new CachedDisplayInfo(size, rotation,
+                windowMetrics.getWindowInsets().getDisplayCutout());
     }
 
     /**
@@ -360,23 +432,30 @@
     }
 
     /**
-     *
      * Returns the display associated with the context, or DEFAULT_DISPLAY if the context isn't
      * associated with a display.
      */
     protected Display getDisplay(Context displayInfoContext) {
-        if (Utilities.ATLEAST_R) {
-            try {
-                return displayInfoContext.getDisplay();
-            } catch (UnsupportedOperationException e) {
-                // Ignore
-            }
+        try {
+            return displayInfoContext.getDisplay();
+        } catch (UnsupportedOperationException e) {
+            // Ignore
         }
         return displayInfoContext.getSystemService(DisplayManager.class).getDisplay(
                 DEFAULT_DISPLAY);
     }
 
     /**
+     * Returns a DisplayCutout which represents a rotated version of the original
+     */
+    protected DisplayCutout rotateCutout(DisplayCutout original, int startWidth, int startHeight,
+            int fromRotation, int toRotation) {
+        Rect safeCutout = getSafeInsets(original);
+        rotateRect(safeCutout, deltaRotation(fromRotation, toRotation));
+        return new DisplayCutout(Insets.of(safeCutout), null, null, null, null);
+    }
+
+    /**
      * Returns the current navigation mode from resource.
      */
     public NavigationMode getNavigationMode(Context context) {
@@ -395,4 +474,15 @@
         return Utilities.ATLEAST_S ? NavigationMode.NO_BUTTON :
                 NavigationMode.THREE_BUTTONS;
     }
+
+    @Override
+    public void close() { }
+
+    /**
+     * @see DisplayCutout#getSafeInsets
+     */
+    public static Rect getSafeInsets(DisplayCutout cutout) {
+        return new Rect(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
+                cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
+    }
 }
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 30e0971..5ce455a 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -25,6 +25,8 @@
 import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS;
 import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
 
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -82,7 +84,6 @@
             };
     protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
     protected static final float TRANSLATION_SHIFT_OPENED = 0f;
-    private static final float VIEW_NO_SCALE = 1f;
     private static final int DEFAULT_DURATION = 300;
 
     protected final T mActivityContext;
@@ -129,9 +130,14 @@
     protected @Nullable OnCloseListener mOnCloseBeginListener;
     protected List<OnCloseListener> mOnCloseListeners = new ArrayList<>();
 
-    protected final AnimatedFloat mSlideInViewScale =
-            new AnimatedFloat(this::onScaleProgressChanged, VIEW_NO_SCALE);
-    protected boolean mIsBackProgressing;
+    /**
+     * How far through a "user initiated dismissal" the UI is. e.g. Predictive back, swipe to home,
+     * 0 is regular state, 1 is fully dismissed.
+     */
+    protected final AnimatedFloat mSwipeToDismissProgress =
+            new AnimatedFloat(this::onUserSwipeToDismissProgressChanged, 0f);
+    protected boolean mIsDismissInProgress;
+    private View mViewToAnimateInSwipeToDismiss = this;
     private @Nullable Drawable mContentBackground;
     private @Nullable View mContentBackgroundParentView;
 
@@ -283,39 +289,77 @@
 
     @Override
     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    public void onBackProgressed(BackEvent backEvent) {
-        final float progress = backEvent.getProgress();
-        float deceleratedProgress =
-                Interpolators.PREDICTIVE_BACK_DECELERATED_EASE.getInterpolation(progress);
-        mIsBackProgressing = progress > 0f;
-        mSlideInViewScale.updateValue(PREDICTIVE_BACK_MIN_SCALE
-                + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1 - deceleratedProgress));
-    }
-
-    protected void onScaleProgressChanged() {
-        float scaleProgress = mSlideInViewScale.value;
-        SCALE_PROPERTY.set(this, scaleProgress);
-        setClipChildren(!mIsBackProgressing);
-        mContent.setClipChildren(!mIsBackProgressing);
-        invalidate();
+    public void onBackStarted(BackEvent backEvent) {
+        super.onBackStarted(backEvent);
+        mViewToAnimateInSwipeToDismiss = shouldAnimateContentViewInBackSwipe() ? mContent : this;
     }
 
     @Override
-    public void onBackInvoked() {
-        super.onBackInvoked();
-        animateSlideInViewToNoScale();
+    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public void onBackProgressed(BackEvent backEvent) {
+        final float progress = backEvent.getProgress();
+        float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(progress);
+        mSwipeToDismissProgress.updateValue(deceleratedProgress);
+    }
+
+    /**
+     * During predictive back swipe, the default behavior is to scale {@link AbstractSlideInView}
+     * during back swipe. This method allow subclass to scale {@link #mContent}, typically to exit
+     * search mode.
+     *
+     * <p>Note that this method can be expensive, and should only be called from
+     * {@link #onBackStarted(BackEvent)}, not from {@link #onBackProgressed(BackEvent)}.
+     */
+    protected boolean shouldAnimateContentViewInBackSwipe() {
+        return false;
+    }
+
+    protected void onUserSwipeToDismissProgressChanged() {
+        float progress = mSwipeToDismissProgress.value;
+        mIsDismissInProgress = progress > 0f;
+
+        float scale = PREDICTIVE_BACK_MIN_SCALE + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1f - progress);
+        SCALE_PROPERTY.set(mViewToAnimateInSwipeToDismiss, scale);
+        setClipChildren(!mIsDismissInProgress);
+        setClipToPadding(!mIsDismissInProgress);
+        mContent.setClipChildren(!mIsDismissInProgress);
+        mContent.setClipToPadding(!mIsDismissInProgress);
+        invalidate();
     }
 
     @Override
     public void onBackCancelled() {
         super.onBackCancelled();
-        animateSlideInViewToNoScale();
+        animateSwipeToDismissProgressToStart();
     }
 
-    protected void animateSlideInViewToNoScale() {
-        mSlideInViewScale.animateToValue(1f)
-                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
-                .start();
+    protected void animateSwipeToDismissProgressToStart() {
+        ObjectAnimator objectAnimator = mSwipeToDismissProgress.animateToValue(0f)
+                .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS);
+
+        // If we are animating a different view, we should reset the animating view back to
+        // AbstractSlideInView as it is the default view to animate.
+        if (this != mViewToAnimateInSwipeToDismiss) {
+            objectAnimator.addListener(new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationCancel(Animator animator) {
+                    mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animator) {}
+
+                @Override
+                public void onAnimationStart(Animator animator) {}
+            });
+        }
+
+        objectAnimator.start();
     }
 
     @Override
@@ -344,15 +388,14 @@
                 mContentBackgroundParentView.getTop() + (int) mContent.getTranslationY(),
                 mContentBackgroundParentView.getRight(),
                 mContentBackgroundParentView.getBottom()
-                        + (mIsBackProgressing ? getBottomOffsetPx() : 0));
+                        + (mIsDismissInProgress ? getBottomOffsetPx() : 0));
         mContentBackground.draw(canvas);
     }
 
     /** Return extra space revealed during predictive back animation. */
     @Px
     protected int getBottomOffsetPx() {
-        final int height = getMeasuredHeight();
-        return (int) ((height / PREDICTIVE_BACK_MIN_SCALE - height) / 2);
+        return (int) (getMeasuredHeight() * (1 - PREDICTIVE_BACK_MIN_SCALE));
     }
 
     /**
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index bef84f7..bf43a22 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -17,13 +17,12 @@
 
 import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
 import static com.android.launcher3.Utilities.allowBGLaunch;
-import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_KEYBOARD_CLOSED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_PENDING_INTENT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
-import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
@@ -150,7 +149,20 @@
      * @return {@code true} if user has selected the first split app and is in the process of
      *         selecting the second
      */
-    default boolean isSplitSelectionEnabled() {
+    default boolean isSplitSelectionActive() {
+        // Overridden
+        return false;
+    }
+
+    /**
+     * Handle user tapping on unsupported target when in split selection mode.
+     * See {@link #isSplitSelectionActive()}
+     *
+     * @return {@code true} if this method will handle the incorrect target selection,
+     *         {@code false} if it could not be handled or if not possible to handle based on
+     *         current split state
+     */
+    default boolean handleIncorrectSplitTargetSelection() {
         // Overridden
         return false;
     }
@@ -266,32 +278,26 @@
         if (root == null) {
             return;
         }
-        if (Utilities.ATLEAST_R) {
-            Preconditions.assertUIThread();
-            //  Hide keyboard with WindowInsetsController if could. In case
-            //  hideSoftInputFromWindow may get ignored by input connection being finished
-            //  when the screen is off.
-            //
-            // In addition, inside IMF, the keyboards are closed asynchronously that launcher no
-            // longer need to post to the message queue.
-            final WindowInsetsController wic = root.getWindowInsetsController();
-            WindowInsets insets = root.getRootWindowInsets();
-            boolean isImeShown = insets != null && insets.isVisible(WindowInsets.Type.ime());
-            if (wic != null) {
-                // Only hide the keyboard if it is actually showing.
-                if (isImeShown) {
-                    StatsLogManager slm = getStatsLogManager();
-                    slm.keyboardStateManager().setKeyboardState(HIDE);
-
-                    // this method cannot be called cross threads
-                    wic.hide(WindowInsets.Type.ime());
-                    slm.logger().log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
-                }
-
-                // If the WindowInsetsController is not null, we end here regardless of whether we
-                // hid the keyboard or not.
-                return;
+        Preconditions.assertUIThread();
+        // Hide keyboard with WindowInsetsController if could. In case hideSoftInputFromWindow may
+        // get ignored by input connection being finished when the screen is off.
+        //
+        // In addition, inside IMF, the keyboards are closed asynchronously that launcher no longer
+        // need to post to the message queue.
+        final WindowInsetsController wic = root.getWindowInsetsController();
+        WindowInsets insets = root.getRootWindowInsets();
+        boolean isImeShown = insets != null && insets.isVisible(WindowInsets.Type.ime());
+        if (wic != null) {
+            // Only hide the keyboard if it is actually showing.
+            if (isImeShown) {
+                // this method cannot be called cross threads
+                wic.hide(WindowInsets.Type.ime());
+                getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_KEYBOARD_CLOSED);
             }
+
+            // If the WindowInsetsController is not null, we end here regardless of whether we hid
+            // the keyboard or not.
+            return;
         }
 
         InputMethodManager imm = root.getContext().getSystemService(InputMethodManager.class);
@@ -316,8 +322,8 @@
     }
 
     /**
-     * Returns if the software keyboard is hidden. Hardware keyboards do not display on screen by
-     * default.
+     * Returns if the software keyboard (including input toolbar) is hidden. Hardware
+     * keyboards do not display on screen by default.
      */
     default boolean isSoftwareKeyboardHidden() {
         if (isHardwareKeyboard()) {
@@ -383,7 +389,7 @@
         boolean isShortcut = (item instanceof WorkspaceItemInfo)
                 && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
                 && !((WorkspaceItemInfo) item).isPromise();
-        if (isShortcut && GO_DISABLE_WIDGETS) {
+        if (isShortcut && !WIDGETS_ENABLED) {
             return null;
         }
         ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index a1cd697..5d2d3f4 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -104,7 +104,7 @@
     protected final Rect mHitRect = new Rect();
 
     @ViewDebug.ExportedProperty(category = "launcher")
-    private final RectF mSystemGestureRegion = new RectF();
+    protected final RectF mSystemGestureRegion = new RectF();
     private int mTouchDispatchState = 0;
 
     protected final T mActivity;
@@ -164,7 +164,7 @@
         return findActiveController(ev);
     }
 
-    private boolean isEventInLauncher(MotionEvent ev) {
+    protected boolean isEventWithinSystemGestureRegion(MotionEvent ev) {
         final float x = ev.getX();
         final float y = ev.getY();
 
@@ -175,7 +175,8 @@
     private TouchController findControllerToHandleTouch(MotionEvent ev) {
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
         if (topView != null
-                && (isEventInLauncher(ev) || topView.canInterceptEventsInSystemGestureRegion())
+                && (isEventWithinSystemGestureRegion(ev)
+                || topView.canInterceptEventsInSystemGestureRegion())
                 && topView.onControllerInterceptTouchEvent(ev)) {
             return topView;
         }
@@ -287,7 +288,7 @@
                 mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW
                         | TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS;
 
-                if (isEventInLauncher(ev)) {
+                if (isEventWithinSystemGestureRegion(ev)) {
                     mTouchDispatchState &= ~TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
                 } else {
                     mTouchDispatchState |= TOUCH_DISPATCHING_FROM_VIEW_GESTURE_REGION;
@@ -551,25 +552,21 @@
 
     @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
-        if (Utilities.ATLEAST_Q) {
-            Insets gestureInsets = insets.getMandatorySystemGestureInsets();
-            int gestureInsetBottom = gestureInsets.bottom;
-            Insets imeInset = Utilities.ATLEAST_R
-                    ? insets.getInsets(WindowInsets.Type.ime())
-                    : Insets.NONE;
-            DeviceProfile dp = mActivity.getDeviceProfile();
-            if (dp.isTaskbarPresent) {
-                // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
-                gestureInsetBottom = ResourceUtils.getNavbarSize(
-                        ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
-            }
-            mSystemGestureRegion.set(
-                    Math.max(gestureInsets.left, imeInset.left),
-                    Math.max(gestureInsets.top, imeInset.top),
-                    Math.max(gestureInsets.right, imeInset.right),
-                    Math.max(gestureInsetBottom, imeInset.bottom)
-            );
+        Insets gestureInsets = insets.getMandatorySystemGestureInsets();
+        int gestureInsetBottom = gestureInsets.bottom;
+        Insets imeInset = insets.getInsets(WindowInsets.Type.ime());
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        if (dp.isTaskbarPresent) {
+            // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
+            gestureInsetBottom = ResourceUtils.getNavbarSize(
+                    ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
         }
+        mSystemGestureRegion.set(
+                Math.max(gestureInsets.left, imeInset.left),
+                Math.max(gestureInsets.top, imeInset.top),
+                Math.max(gestureInsets.right, imeInset.right),
+                Math.max(gestureInsetBottom, imeInset.bottom)
+        );
         return super.dispatchApplyWindowInsets(insets);
     }
 }
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index 87e496e..5d3fa9b 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -25,7 +25,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -36,7 +35,6 @@
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
@@ -55,7 +53,6 @@
  * Supports springing just the foreground layer.
  * Supports clipping the icon to/from its icon shape.
  */
-@TargetApi(Build.VERSION_CODES.Q)
 public class ClipIconView extends View implements ClipPathView {
 
     private static final Rect sTmpRect = new Rect();
@@ -112,7 +109,7 @@
         float scaleY = rect.height() / minSize;
         float scale = Math.max(1f, Math.min(scaleX, scaleY));
 
-        if (Float.isNaN(scale)) {
+        if (Float.isNaN(scale) || Float.isInfinite(scale)) {
             // Views are no longer laid out, do not update.
             return;
         }
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 32c70a3..f560311 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -24,14 +24,12 @@
 import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
 
 import android.animation.Animator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.os.CancellationSignal;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -57,6 +55,7 @@
 import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.popup.SystemShortcut;
@@ -67,7 +66,6 @@
 /**
  * A view that is created to look like another view with the purpose of creating fluid animations.
  */
-@TargetApi(Build.VERSION_CODES.Q)
 public class FloatingIconView extends FrameLayout implements
         Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView {
 
@@ -285,6 +283,8 @@
         } else if (btvIcon instanceof PreloadIconDrawable) {
             // Force the progress bar to display.
             drawable = btvIcon;
+        } else if (originalView instanceof ImageView) {
+            drawable = ((ImageView) originalView).getDrawable();
         } else {
             int width = (int) pos.width();
             int height = (int) pos.height();
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index bfb75f0..cab7982 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -15,17 +15,16 @@
  */
 package com.android.launcher3.views;
 
+import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
 import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
 
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Picture;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
@@ -47,7 +46,6 @@
  * Similar to {@link FloatingIconView} but displays a surface with the targetIcon. It then passes
  * the surfaceHandle to the {@link GestureNavContract}.
  */
-@TargetApi(Build.VERSION_CODES.R)
 public class FloatingSurfaceView extends AbstractFloatingView implements
         OnGlobalLayoutListener, Insettable, SurfaceHolder.Callback2 {
 
@@ -162,7 +160,7 @@
         if (mContract == null) {
             return;
         }
-        View icon = mLauncher.getFirstMatchForAppClose(-1,
+        View icon = mLauncher.getFirstMatchForAppClose(NO_MATCHING_ID,
                 mContract.componentName.getPackageName(), mContract.user,
                 false /* supportsAllAppsState */);
 
@@ -178,7 +176,6 @@
 
             if (!mTmpPosition.equals(mIconPosition)) {
                 mIconPosition.set(mTmpPosition);
-                sendIconInfo();
 
                 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
                 lp.width = Math.round(mIconPosition.width());
@@ -187,6 +184,9 @@
                 lp.topMargin = Math.round(mIconPosition.top);
             }
         }
+
+        sendIconInfo();
+
         if (mIcon != null && iconChanged && !mIconBounds.isEmpty()) {
             // Record the icon display
             setCurrentIconVisible(true);
@@ -200,7 +200,7 @@
     }
 
     private void sendIconInfo() {
-        if (mContract != null && !mIconPosition.isEmpty()) {
+        if (mContract != null) {
             mContract.sendEndPosition(mIconPosition, mLauncher, mSurfaceView.getSurfaceControl());
         }
     }
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5cdad03..62eed5c 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -17,6 +17,7 @@
 
 import static androidx.core.content.ContextCompat.getColorStateList;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
 import static com.android.launcher3.LauncherState.EDIT_MODE;
 import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -47,7 +48,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.StatsLogManager.EventEnum;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.ArrowPopup;
 import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -207,7 +207,7 @@
                 R.drawable.ic_palette,
                 IGNORE,
                 OptionsPopupView::startWallpaperPicker));
-        if (!WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (WIDGETS_ENABLED) {
             options.add(new OptionItem(launcher,
                     R.string.widget_button_text,
                     R.drawable.ic_widget,
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index c0b24fa..df8f635 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -30,7 +30,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.Build;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Property;
@@ -40,7 +40,6 @@
 import android.view.WindowInsets;
 import android.widget.TextView;
 
-import androidx.annotation.RequiresApi;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.FastScrollRecyclerView;
@@ -123,7 +122,7 @@
     // Fast scroller popup
     private TextView mPopupView;
     private boolean mPopupVisible;
-    private String mPopupSectionName;
+    private CharSequence mPopupSectionName;
     private Insets mSystemGestureInsets;
 
     protected FastScrollRecyclerView mRv;
@@ -309,13 +308,13 @@
         // Update the fastscroller section name at this touch position
         int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
         float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
-        String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
+        CharSequence sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
         if (!sectionName.equals(mPopupSectionName)) {
             mPopupSectionName = sectionName;
             mPopupView.setText(sectionName);
             performHapticFeedback(CLOCK_TICK);
         }
-        animatePopupVisibility(!sectionName.isEmpty());
+        animatePopupVisibility(!TextUtils.isEmpty(sectionName));
         mLastTouchY = boundedY;
         setThumbOffsetY((int) mLastTouchY);
     }
@@ -352,26 +351,21 @@
         float r = getScrollThumbRadius();
         mThumbBounds.set(-halfW, 0, halfW, mThumbHeight);
         canvas.drawRoundRect(mThumbBounds, r, r, mThumbPaint);
-        if (Utilities.ATLEAST_Q) {
-            mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
-            // swiping very close to the thumb area (not just within it's bound)
-            // will also prevent back gesture
-            SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
-            if (Utilities.ATLEAST_Q && mSystemGestureInsets != null) {
-                SYSTEM_GESTURE_EXCLUSION_RECT.get(0).left =
-                        SYSTEM_GESTURE_EXCLUSION_RECT.get(0).right - mSystemGestureInsets.right;
-            }
-            setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
+        mThumbBounds.roundOut(SYSTEM_GESTURE_EXCLUSION_RECT.get(0));
+        // swiping very close to the thumb area (not just within it's bound)
+        // will also prevent back gesture
+        SYSTEM_GESTURE_EXCLUSION_RECT.get(0).offset(mThumbDrawOffset.x, mThumbDrawOffset.y);
+        if (mSystemGestureInsets != null) {
+            SYSTEM_GESTURE_EXCLUSION_RECT.get(0).left =
+                    SYSTEM_GESTURE_EXCLUSION_RECT.get(0).right - mSystemGestureInsets.right;
         }
+        setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT);
         canvas.restoreToCount(saveCount);
     }
 
     @Override
-    @RequiresApi(Build.VERSION_CODES.Q)
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        if (Utilities.ATLEAST_Q) {
-            mSystemGestureInsets = insets.getSystemGestureInsets();
-        }
+        mSystemGestureInsets = insets.getSystemGestureInsets();
         return super.onApplyWindowInsets(insets);
     }
 
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index ca80c51..f6c4984 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -26,6 +26,7 @@
 import android.view.View;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Px;
 import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.BaseActivity;
@@ -187,9 +188,19 @@
      * A Utility interface allowing for other surfaces to draw on ScrimView
      */
     public interface ScrimDrawingController {
-        /**
-         * Called inside ScrimView#OnDraw
-         */
-        void drawOnScrimWithScale(Canvas canvas, float scale);
+
+        /** Draw scrim view on canvas with scale. */
+        default void drawOnScrimWithScale(Canvas canvas, float scale) {
+            drawOnScrimWithScaleAndBottomOffset(canvas, scale, 0);
+        }
+
+        /** Draw scrim view on canvas with bottomOffset. */
+        default void drawOnScrimWithBottomOffset(Canvas canvas, @Px int bottomOffsetPx) {
+            drawOnScrimWithScaleAndBottomOffset(canvas, 1f, bottomOffsetPx);
+        }
+
+        /** Draw scrim view on canvas with scale and bottomOffset. */
+        void drawOnScrimWithScaleAndBottomOffset(
+                Canvas canvas, float scale, @Px int bottomOffsetPx);
     }
 }
diff --git a/src/com/android/launcher3/views/StickyHeaderLayout.java b/src/com/android/launcher3/views/StickyHeaderLayout.java
index d6481a9..090251f 100644
--- a/src/com/android/launcher3/views/StickyHeaderLayout.java
+++ b/src/com/android/launcher3/views/StickyHeaderLayout.java
@@ -36,6 +36,9 @@
 
 import com.android.launcher3.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * A {@link LinearLayout} container which allows scrolling parts of its content based on the
  * scroll of a different view. Views which are marked as sticky are not scrolled, giving the
@@ -242,6 +245,22 @@
         return p instanceof MyLayoutParams;
     }
 
+    /**
+     * Return a list of all the children that have the sticky layout param set.
+     */
+    public List<View> getStickyChildren() {
+        List<View> stickyChildren = new ArrayList<>();
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View v = getChildAt(i);
+            MyLayoutParams lp = (MyLayoutParams) v.getLayoutParams();
+            if (lp.sticky) {
+                stickyChildren.add(v);
+            }
+        }
+        return stickyChildren;
+    }
+
     private static class MyLayoutParams extends LayoutParams {
 
         public final boolean sticky;
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
index 40c6115..53fbd8f 100644
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -59,6 +59,7 @@
         mContent = findViewById(R.id.edu_view);
         findViewById(R.id.edu_close_button)
                 .setOnClickListener(v -> close(/* animate= */ true));
+        setContentBackgroundWithParent(mContent.getBackground(), mContent);
     }
 
     @Override
@@ -68,6 +69,12 @@
                 mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
     }
 
+    @Override
+    protected void onUserSwipeToDismissProgressChanged() {
+        super.onUserSwipeToDismissProgressChanged();
+        setTranslationY(getMeasuredHeight() * (mSwipeToDismissProgress.value / 2));
+    }
+
     private void show() {
         attachToContainer();
         animateOpen();
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
index 80b1cdd..4f5d311 100644
--- a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher3.widget;
 
-import static com.android.launcher3.Utilities.ATLEAST_R;
-
 import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.Insets;
@@ -153,17 +151,10 @@
     @SuppressLint("NewApi") // Already added API check.
     @Override
     public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
-        if (ATLEAST_R) {
-            Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
-            mInsets.set(insets.left, insets.top, insets.right, insets.bottom);
-        } else {
-            mInsets.set(windowInsets.getSystemWindowInsetLeft(),
-                    windowInsets.getSystemWindowInsetTop(),
-                    windowInsets.getSystemWindowInsetRight(),
-                    windowInsets.getSystemWindowInsetBottom());
-        }
-        mContent.setPadding(mContent.getPaddingStart(),
-                mContent.getPaddingTop(), mContent.getPaddingEnd(), mInsets.bottom);
+        Insets insets = windowInsets.getInsets(WindowInsets.Type.systemBars());
+        mInsets.set(insets.left, insets.top, insets.right, insets.bottom);
+        mContent.setPadding(mContent.getPaddingStart(), mContent.getPaddingTop(),
+                mContent.getPaddingEnd(), mInsets.bottom);
 
         int contentHorizontalMarginInPx = getResources().getDimensionPixelSize(
                 R.dimen.widget_list_horizontal_margin);
diff --git a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
index 580b4f1..104209e 100644
--- a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
@@ -34,6 +34,17 @@
  */
 public abstract class BaseLauncherAppWidgetHostView extends NavigableAppWidgetHostView {
 
+    private static final ViewOutlineProvider VIEW_OUTLINE_PROVIDER = new ViewOutlineProvider() {
+        @Override
+        public void getOutline(View view, Outline outline) {
+            // Since ShortcutAndWidgetContainer sets clipChildren to false, we should restrict the
+            // outline to be the view bounds, otherwise widgets might draw themselves outside of
+            // the launcher view. Setting alpha to 0 to match the previous behavior.
+            outline.setRect(0, 0, view.getWidth(), view.getHeight());
+            outline.setAlpha(.0f);
+        }
+    };
+
     protected final LayoutInflater mInflater;
 
     private final Rect mEnforcedRectangle = new Rect();
@@ -49,10 +60,13 @@
         }
     };
 
+    private boolean mIsCornerRadiusEnforced;
+
     public BaseLauncherAppWidgetHostView(Context context) {
         super(context);
 
         setExecutor(Executors.THREAD_POOL_EXECUTOR);
+        setClipToOutline(true);
 
         mInflater = LayoutInflater.from(context);
         mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(getContext());
@@ -84,8 +98,8 @@
 
     @UiThread
     private void resetRoundedCorners() {
-        setOutlineProvider(ViewOutlineProvider.BACKGROUND);
-        setClipToOutline(false);
+        setOutlineProvider(VIEW_OUTLINE_PROVIDER);
+        mIsCornerRadiusEnforced = false;
     }
 
     @UiThread
@@ -104,7 +118,7 @@
                 background,
                 mEnforcedRectangle);
         setOutlineProvider(mCornerRadiusEnforcementOutline);
-        setClipToOutline(true);
+        mIsCornerRadiusEnforced = true;
         invalidateOutline();
     }
 
@@ -115,6 +129,6 @@
 
     /** Returns true if the corner radius are enforced for this App Widget. */
     public boolean hasEnforcedCornerRadius() {
-        return getClipToOutline();
+        return mIsCornerRadiusEnforced;
     }
 }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 5171fa2..749554c 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,20 +16,23 @@
 package com.android.launcher3.widget;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
+import static com.android.launcher3.Flags.enableWidgetTapToAdd;
 import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
 
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
 import android.view.WindowInsets;
 import android.view.animation.Interpolator;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
 import androidx.core.view.ViewCompat;
@@ -40,6 +43,7 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.popup.PopupDataProvider;
@@ -51,6 +55,8 @@
 import com.android.launcher3.views.AbstractSlideInView;
 import com.android.launcher3.views.ArrowTipView;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 /**
  * Base class for various widgets popup
  */
@@ -62,24 +68,35 @@
 
     protected final Rect mInsets = new Rect();
 
-    @Px protected int mContentHorizontalMargin;
-    @Px protected int mWidgetCellHorizontalPadding;
+    @Px
+    protected int mContentHorizontalMargin;
+    @Px
+    protected int mWidgetCellHorizontalPadding;
 
     protected int mNavBarScrimHeight;
     private final Paint mNavBarScrimPaint;
 
     private boolean mDisableNavBarScrim = false;
 
+    @Nullable private WidgetCell mWidgetCellWithAddButton = null;
+
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mContentHorizontalMargin = getResources().getDimensionPixelSize(
-                R.dimen.widget_list_horizontal_margin);
+        mContentHorizontalMargin = getWidgetListHorizontalMargin();
         mWidgetCellHorizontalPadding = getResources().getDimensionPixelSize(
                 R.dimen.widget_cell_horizontal_padding);
         mNavBarScrimPaint = new Paint();
         mNavBarScrimPaint.setColor(Themes.getNavBarScrimColor(mActivityContext));
     }
 
+    /**
+     * Returns the margins to be applied to the left and right of the widget apps list.
+     */
+    protected int getWidgetListHorizontalMargin() {
+        return getResources().getDimensionPixelSize(
+                R.dimen.widget_list_horizontal_margin);
+    }
+
     protected int getScrimColor(Context context) {
         return context.getResources().getColor(R.color.widgets_picker_scrim);
     }
@@ -113,13 +130,117 @@
 
     @Override
     public final void onClick(View v) {
-        if (v instanceof WidgetCell) {
-            mActivityContext.getItemOnClickListener().onClick(v);
-        } else if (v.getParent() instanceof WidgetCell wc) {
+        WidgetCell wc;
+        if (v instanceof WidgetCell view) {
+            wc = view;
+        }  else if (v.getParent() instanceof WidgetCell parent) {
+            wc = parent;
+        } else {
+            return;
+        }
+
+        if (enableWidgetTapToAdd()) {
+            scrollToWidgetCell(wc);
+
+            if (mWidgetCellWithAddButton != null) {
+                if (mWidgetCellWithAddButton.isShowingAddButton()) {
+                    // If there is a add button currently showing, hide it.
+                    mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+                } else {
+                    // The last recorded widget cell to show an add button is no longer showing it,
+                    // likely because the widget cell has been recycled or lost focus. If this is
+                    // the cell that has been clicked, we will show it below.
+                    mWidgetCellWithAddButton = null;
+                }
+            }
+
+            if (mWidgetCellWithAddButton != wc) {
+                // If click is on a cell not showing an add button, show it now.
+                final PendingAddItemInfo info = (PendingAddItemInfo) wc.getTag();
+                if (mActivityContext instanceof Launcher) {
+                    wc.showAddButton((view) -> addWidget(info));
+                } else {
+                    wc.showAddButton((view) -> mActivityContext.getItemOnClickListener()
+                            .onClick(wc));
+                }
+            }
+
+            mWidgetCellWithAddButton = mWidgetCellWithAddButton != wc ? wc : null;
+        } else {
             mActivityContext.getItemOnClickListener().onClick(wc);
         }
     }
 
+    /**
+     * Click handler for tap to add button.
+     */
+    private void addWidget(@NonNull PendingAddItemInfo info) {
+        // Using a boolean flag here to make sure the callback is only run once. This should never
+        // happen because we close the sheet and it will be reconstructed the next time it is
+        // needed.
+        final AtomicBoolean hasRun = new AtomicBoolean(false);
+        addOnCloseListener(() -> {
+            if (!hasRun.get()) {
+                Launcher.getLauncher(mActivityContext).getAccessibilityDelegate().addToWorkspace(
+                        info, /*accessibility=*/ false,
+                        /*finishCallback=*/ (success) -> {
+                            mActivityContext.getStatsLogManager()
+                                    .logger()
+                                    .withItemInfo(info)
+                                    .log(LAUNCHER_WIDGET_ADD_BUTTON_TAP);
+                        });
+                hasRun.set(true);
+            }
+        });
+        handleClose(true);
+    }
+
+    /**
+     * Scroll to show the widget cell. If both the bottom and top of the cell are clipped, this will
+     * prioritize showing the bottom of the cell (where the add button is).
+     */
+    private void scrollToWidgetCell(@NonNull WidgetCell wc) {
+        final int headerTopClip = getHeaderTopClip(wc);
+        final Rect visibleRect = new Rect();
+        final boolean isPartiallyVisible = wc.getLocalVisibleRect(visibleRect);
+        int scrollByY = 0;
+        if (isPartiallyVisible) {
+            final int scrollPadding = getResources()
+                    .getDimensionPixelSize(R.dimen.widget_cell_add_button_scroll_padding);
+            final int topClip = visibleRect.top + headerTopClip;
+            final int bottomClip = wc.getHeight() - visibleRect.bottom;
+            if (bottomClip != 0) {
+                scrollByY = bottomClip + scrollPadding;
+            } else if (topClip != 0) {
+                scrollByY = -topClip - scrollPadding;
+            }
+        }
+
+        if (isPartiallyVisible && scrollByY == 0) {
+            // Widget is fully visible.
+            return;
+        } else if (!isPartiallyVisible) {
+            Log.e("BaseWidgetSheet", "click on invisible WidgetCell should not be possible");
+            return;
+        }
+
+        scrollCellContainerByY(wc, scrollByY);
+    }
+
+    /**
+     * Find the nearest scrollable container of the given WidgetCell, and scroll by the given
+     * amount.
+     */
+    protected abstract void scrollCellContainerByY(WidgetCell wc, int scrollByY);
+
+
+    /**
+     * Return the top clip of any sticky headers over the given cell.
+     */
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        return 0;
+    }
+
     @Override
     public boolean onLongClick(View v) {
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
@@ -142,8 +263,7 @@
     @Override
     public void setInsets(Rect insets) {
         mInsets.set(insets);
-        @Px int contentHorizontalMargin = getResources().getDimensionPixelSize(
-                R.dimen.widget_list_horizontal_margin);
+        @Px int contentHorizontalMargin = getWidgetListHorizontalMargin();
         if (contentHorizontalMargin != mContentHorizontalMargin) {
             onContentHorizontalMarginChanged(contentHorizontalMargin);
             mContentHorizontalMargin = contentHorizontalMargin;
@@ -158,10 +278,8 @@
     private int getNavBarScrimHeight(WindowInsets insets) {
         if (mDisableNavBarScrim) {
             return 0;
-        } else if (Utilities.ATLEAST_Q) {
-            return insets.getTappableElementInsets().bottom;
         } else {
-            return insets.getStableInsetBottom();
+            return insets.getTappableElementInsets().bottom;
         }
     }
 
@@ -192,7 +310,7 @@
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (deviceProfile.isTablet) {
-            widthUsed = Math.max(2 * getTabletMargin(deviceProfile),
+            widthUsed = Math.max(2 * getTabletHorizontalMargin(deviceProfile),
                     2 * (mInsets.left + mInsets.right));
         } else if (mInsets.bottom > 0) {
             widthUsed = mInsets.left + mInsets.right;
@@ -208,15 +326,8 @@
                 MeasureSpec.getSize(heightMeasureSpec));
     }
 
-    private int getTabletMargin(DeviceProfile deviceProfile) {
-        if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
-            return getResources().getDimensionPixelSize(
-                    R.dimen.widget_picker_landscape_tablet_left_right_margin);
-        }
-        if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
-            return getResources().getDimensionPixelSize(
-                    R.dimen.widget_picker_two_panels_left_right_margin);
-        }
+    /** Returns the horizontal margins to be applied to the widget sheet. **/
+    protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
         return deviceProfile.allAppsLeftRightMargin;
     }
 
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 99485be..aab78bd 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -41,9 +41,9 @@
 import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.ShadowGenerator;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.util.WidgetSizes;
@@ -74,12 +74,12 @@
      * @return a request id which can be used to cancel the request.
      */
     @NonNull
-    public HandlerRunnable loadPreview(
+    public CancellableTask loadPreview(
             @NonNull WidgetItem item,
             @NonNull Size previewSize,
             @NonNull Consumer<Bitmap> callback) {
         Handler handler = Executors.UI_HELPER_EXECUTOR.getHandler();
-        HandlerRunnable<Bitmap> request = new HandlerRunnable<>(handler,
+        CancellableTask<Bitmap> request = new CancellableTask<>(
                 () -> generatePreview(item, previewSize.getWidth(), previewSize.getHeight()),
                 MAIN_EXECUTOR,
                 callback);
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
deleted file mode 100644
index f42142e..0000000
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.text.Layout;
-import android.text.StaticLayout;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.util.TypedValue;
-import android.view.View;
-import android.widget.RemoteViews;
-
-import com.android.launcher3.R;
-
-/**
- * A widget host views created while the host has not bind to the system service.
- */
-public class DeferredAppWidgetHostView extends LauncherAppWidgetHostView {
-
-    private final TextPaint mPaint;
-    private Layout mSetupTextLayout;
-
-    public DeferredAppWidgetHostView(Context context) {
-        super(context);
-        setWillNotDraw(false);
-
-        mPaint = new TextPaint();
-        mPaint.setColor(Color.WHITE);
-        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                mLauncher.getDeviceProfile().iconTextSizePx,
-                getResources().getDisplayMetrics()));
-        setBackgroundResource(R.drawable.bg_deferred_app_widget);
-    }
-
-    @Override
-    public void updateAppWidget(RemoteViews remoteViews) {
-        // Not allowed
-    }
-
-    @Override
-    public void addView(View child) {
-        // Not allowed
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        AppWidgetProviderInfo info = getAppWidgetInfo();
-        if (info == null || TextUtils.isEmpty(info.label)) {
-            return;
-        }
-
-        // Use double padding so that there is extra space between background and text if possible.
-        int availableWidth = getMeasuredWidth() - 2 * (getPaddingLeft() + getPaddingRight());
-        if (availableWidth <= 0) {
-            availableWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
-        }
-        if (mSetupTextLayout != null && mSetupTextLayout.getText().equals(info.label)
-                && mSetupTextLayout.getWidth() == availableWidth) {
-            return;
-        }
-        mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
-                Layout.Alignment.ALIGN_CENTER, 1, 0, true);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mSetupTextLayout != null) {
-            canvas.translate((getWidth() - mSetupTextLayout.getWidth()) / 2,
-                    (getHeight() - mSetupTextLayout.getHeight()) / 2);
-            mSetupTextLayout.draw(canvas);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
index 9c21ea2..40c3984 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java
@@ -21,13 +21,22 @@
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.RemoteViews;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.WeakHashMap;
 import java.util.function.IntConsumer;
 
 /**
@@ -37,8 +46,7 @@
  */
 class LauncherAppWidgetHost extends AppWidgetHost {
     @NonNull
-    private final ArrayList<LauncherWidgetHolder.ProviderChangedListener>
-            mProviderChangeListeners = new ArrayList<>();
+    private final List<ProviderChangedListener> mProviderChangeListeners;
 
     @NonNull
     private final Context mContext;
@@ -46,33 +54,16 @@
     @Nullable
     private final IntConsumer mAppWidgetRemovedCallback;
 
-    @NonNull
-    private final LauncherWidgetHolder mHolder;
+    @Nullable
+    private ListenableHostView mViewToRecycle;
 
     public LauncherAppWidgetHost(@NonNull Context context,
-            @Nullable IntConsumer appWidgetRemovedCallback, @NonNull LauncherWidgetHolder holder) {
+            @Nullable IntConsumer appWidgetRemovedCallback,
+            List<ProviderChangedListener> providerChangeListeners) {
         super(context, APPWIDGET_HOST_ID);
         mContext = context;
         mAppWidgetRemovedCallback = appWidgetRemovedCallback;
-        mHolder = holder;
-    }
-
-    /**
-     * Add a listener that is triggered when the providers of the widgets are changed
-     * @param listener The listener that notifies when the providers changed
-     */
-    public void addProviderChangeListener(
-            @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
-        mProviderChangeListeners.add(listener);
-    }
-
-    /**
-     * Remove the specified listener from the host
-     * @param listener The listener that is to be removed from the host
-     */
-    public void removeProviderChangeListener(
-            LauncherWidgetHolder.ProviderChangedListener listener) {
-        mProviderChangeListeners.remove(listener);
+        mProviderChangeListeners = providerChangeListeners;
     }
 
     @Override
@@ -85,11 +76,21 @@
         }
     }
 
+    /**
+     * Sets the view to be recycled for the next widget creation.
+     */
+    public void recycleViewForNextCreation(ListenableHostView viewToRecycle) {
+        mViewToRecycle = viewToRecycle;
+    }
+
     @Override
     @NonNull
     public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
             AppWidgetProviderInfo appWidget) {
-        return mHolder.onCreateView(context, appWidgetId, appWidget);
+        ListenableHostView result =
+                mViewToRecycle != null ? mViewToRecycle : new ListenableHostView(context);
+        mViewToRecycle = null;
+        return result;
     }
 
     /**
@@ -115,7 +116,10 @@
         if (mAppWidgetRemovedCallback == null) {
             return;
         }
-        mAppWidgetRemovedCallback.accept(appWidgetId);
+        // Route the call via model thread, in case it comes while a loader-bind is in progress
+        Executors.MODEL_EXECUTOR.execute(
+                () -> Executors.MAIN_EXECUTOR.execute(
+                        () -> mAppWidgetRemovedCallback.accept(appWidgetId)));
     }
 
     /**
@@ -126,4 +130,36 @@
         super.clearViews();
     }
 
+    public static class ListenableHostView extends LauncherAppWidgetHostView {
+
+        private Set<Runnable> mUpdateListeners = Collections.EMPTY_SET;
+
+        ListenableHostView(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void updateAppWidget(RemoteViews remoteViews) {
+            super.updateAppWidget(remoteViews);
+            mUpdateListeners.forEach(Runnable::run);
+        }
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+            super.onInitializeAccessibilityNodeInfo(info);
+            info.setClassName(LauncherAppWidgetHostView.class.getName());
+        }
+
+        /**
+         * Adds a callback to be run everytime the provided app widget updates.
+         * @return a closable to remove this callback
+         */
+        public SafeCloseable addUpdateListener(Runnable callback) {
+            if (mUpdateListeners == Collections.EMPTY_SET) {
+                mUpdateListeners = Collections.newSetFromMap(new WeakHashMap<>());
+            }
+            mUpdateListeners.add(callback);
+            return () -> mUpdateListeners.remove(callback);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index 5d069ed..c3e9ad6 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -16,11 +16,9 @@
 
 package com.android.launcher3.widget;
 
-import android.annotation.TargetApi;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -41,14 +39,13 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.CheckLongPressHelper;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
 
 /**
@@ -75,7 +72,7 @@
 
     private final Rect mTempRect = new Rect();
     private final CheckLongPressHelper mLongPressHelper;
-    protected final Launcher mLauncher;
+    protected final ActivityContext mActivityContext;
 
     // Maintain the color manager.
     private final LocalColorExtractor mColorExtractor;
@@ -95,16 +92,21 @@
 
     private boolean mTrackingWidgetUpdate = false;
 
-    private boolean mIsWidgetCachingDisabled = false;
+    private int mFocusRectOutsets = 0;
 
     public LauncherAppWidgetHostView(Context context) {
         super(context);
-        mLauncher = Launcher.getLauncher(context);
+        mActivityContext = ActivityContext.lookupContext(context);
         mLongPressHelper = new CheckLongPressHelper(this, this);
-        setAccessibilityDelegate(mLauncher.getAccessibilityDelegate());
+        setAccessibilityDelegate(mActivityContext.getAccessibilityDelegate());
         setBackgroundResource(R.drawable.widget_internal_focus_bg);
+        if (Flags.enableFocusOutline()) {
+            setDefaultFocusHighlightEnabled(false);
+            mFocusRectOutsets = context.getResources().getDimensionPixelSize(
+                    R.dimen.focus_rect_widget_outsets);
+        }
 
-        if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) {
+        if (Themes.getAttrBoolean(context, R.attr.isWorkspaceDarkText)) {
             setOnLightBackground(true);
         }
         mColorExtractor = new LocalColorExtractor(); // no-op
@@ -122,50 +124,35 @@
     @Override
     public boolean onLongClick(View view) {
         if (mIsScrollable) {
-            DragLayer dragLayer = mLauncher.getDragLayer();
-            dragLayer.requestDisallowInterceptTouchEvent(false);
+            mActivityContext.getDragLayer().requestDisallowInterceptTouchEvent(false);
         }
         view.performLongClick();
         return true;
     }
 
     @Override
-    @TargetApi(Build.VERSION_CODES.Q)
     public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
         super.setAppWidget(appWidgetId, info);
-        if (!mTrackingWidgetUpdate && Utilities.ATLEAST_Q) {
+        if (!mTrackingWidgetUpdate) {
             mTrackingWidgetUpdate = true;
             Trace.beginAsyncSection(TRACE_METHOD_NAME + info.provider, appWidgetId);
             Log.i(TAG, "App widget created with id: " + appWidgetId);
         }
     }
 
-    public void setIsWidgetCachingDisabled(boolean isWidgetCachingDisabled) {
-        mIsWidgetCachingDisabled = isWidgetCachingDisabled;
-    }
-
     @Override
-    @TargetApi(Build.VERSION_CODES.Q)
     public void updateAppWidget(RemoteViews remoteViews) {
-        if (mTrackingWidgetUpdate && remoteViews != null && Utilities.ATLEAST_Q) {
+        if (mTrackingWidgetUpdate && remoteViews != null) {
             Log.i(TAG, "App widget with id: " + getAppWidgetId() + " loaded");
             Trace.endAsyncSection(
                     TRACE_METHOD_NAME + getAppWidgetInfo().provider, getAppWidgetId());
             mTrackingWidgetUpdate = false;
         }
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()
-                && !mIsWidgetCachingDisabled) {
+        if (isDeferringUpdates()) {
             mLastRemoteViews = remoteViews;
-            if (isDeferringUpdates()) {
-                return;
-            }
-        } else {
-            if (isDeferringUpdates()) {
-                mLastRemoteViews = remoteViews;
-                return;
-            }
-            mLastRemoteViews = null;
+            return;
         }
+        mLastRemoteViews = null;
 
         super.updateAppWidget(remoteViews);
 
@@ -234,7 +221,7 @@
 
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
-            DragLayer dragLayer = mLauncher.getDragLayer();
+            BaseDragLayer dragLayer = mActivityContext.getDragLayer();
             if (mIsScrollable) {
                 dragLayer.requestDisallowInterceptTouchEvent(true);
             }
@@ -286,6 +273,13 @@
     }
 
     @Override
+    public void getFocusedRect(Rect r) {
+        super.getFocusedRect(r);
+        // Outset to a larger rect for drawing a padding between focus outline and widget
+        r.inset(mFocusRectOutsets, mFocusRectOutsets);
+    }
+
+    @Override
     public void onTouchComplete() {
         if (!mLongPressHelper.hasPerformedLongPress()) {
             // If a long press has been performed, we don't want to clear the record of that since
@@ -299,8 +293,7 @@
         super.onLayout(changed, left, top, right, bottom);
         mIsScrollable = checkScrollableRecursively(this);
 
-        if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
-            LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+        if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo info) {
             mTempRect.set(left, top, right, bottom);
             mColorExtractor.setWorkspaceLocation(mTempRect, (View) getParent(), info.screenId);
         }
@@ -434,26 +427,9 @@
         scheduleNextAdvance();
     }
 
-    public void reInflate() {
-        if (!isAttachedToWindow()) {
-            return;
-        }
-        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
-        if (info == null) {
-            // This occurs when LauncherAppWidgetHostView is used to render a preview layout.
-            return;
-        }
-        // Remove and rebind the current widget (which was inflated in the wrong
-        // orientation), but don't delete it from the database
-        mLauncher.removeItem(this, info, false  /* deleteFromDb */,
-                "widget removed because of configuration change");
-        mLauncher.bindAppWidget(info);
-    }
-
     @Override
     protected boolean shouldAllowDirectClick() {
-        if (getTag() instanceof ItemInfo) {
-            ItemInfo item = (ItemInfo) getTag();
+        if (getTag() instanceof ItemInfo item) {
             return item.spanX == 1 && item.spanY == 1;
         }
         return false;
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index ef51d15..3e4fd8c 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -15,7 +15,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.ComponentWithLabelAndIcon;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -206,11 +205,7 @@
     }
 
     public int getWidgetFeatures() {
-        if (Utilities.ATLEAST_P) {
-            return widgetFeatures;
-        } else {
-            return 0;
-        }
+        return widgetFeatures;
     }
 
     public boolean isReconfigurable() {
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 6acc83d..a5e22c5 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -17,7 +17,10 @@
 
 import static android.app.Activity.RESULT_CANCELED;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+import static com.android.launcher3.Flags.enableWorkspaceInflation;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
 
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetHostView;
@@ -27,8 +30,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
+import android.os.Looper;
 import android.util.SparseArray;
-import android.widget.RemoteViews;
 import android.widget.Toast;
 
 import androidx.annotation.NonNull;
@@ -36,17 +39,18 @@
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseDraggingActivity;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.widget.LauncherAppWidgetHost.ListenableHostView;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.IntConsumer;
 
 /**
@@ -64,17 +68,14 @@
             FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED;
 
     @NonNull
-    private final Context mContext;
+    protected final Context mContext;
 
     @NonNull
     private final AppWidgetHost mWidgetHost;
 
     @NonNull
-    private final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
-    @NonNull
-    private final SparseArray<PendingAppWidgetHostView> mPendingViews = new SparseArray<>();
-    @NonNull
-    private final SparseArray<LauncherAppWidgetHostView> mDeferredViews = new SparseArray<>();
+    protected final SparseArray<LauncherAppWidgetHostView> mViews = new SparseArray<>();
+    protected final List<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
 
     protected int mFlags = FLAG_STATE_IS_NORMAL;
 
@@ -91,17 +92,18 @@
 
     protected AppWidgetHost createHost(
             Context context, @Nullable IntConsumer appWidgetRemovedCallback) {
-        return new LauncherAppWidgetHost(context, appWidgetRemovedCallback, this);
+        return new LauncherAppWidgetHost(
+                context, appWidgetRemovedCallback, mProviderChangedListeners);
     }
 
     /**
      * Starts listening to the widget updates from the server side
      */
     public void startListening() {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return;
         }
-        setListeningFlag(true);
+
         try {
             mWidgetHost.startListening();
         } catch (Exception e) {
@@ -113,6 +115,8 @@
             // have been established by this point, and we will end up populating the
             // widgets upon bind anyway. See issue 14255011 for more context.
         }
+        // TODO: Investigate why widgetHost.startListening() always return non-empty updates
+        setListeningFlag(true);
 
         updateDeferredView();
     }
@@ -121,25 +125,12 @@
      * Update any views which have been deferred because the host was not listening.
      */
     protected void updateDeferredView() {
+        // Update any views which have been deferred because the host was not listening.
         // We go in reverse order and inflate any deferred or cached widget
         for (int i = mViews.size() - 1; i >= 0; i--) {
             LauncherAppWidgetHostView view = mViews.valueAt(i);
-            if (view instanceof DeferredAppWidgetHostView) {
-                view.reInflate();
-            }
-            if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-                final int appWidgetId = mViews.keyAt(i);
-                if (view == mDeferredViews.get(appWidgetId)) {
-                    // If the widget view was deferred, we'll need to call super.createView here
-                    // to make the binder call to system process to fetch cumulative updates to this
-                    // widget, as well as setting up this view for future updates.
-                    mWidgetHost.createView(view.mLauncher, appWidgetId,
-                            view.getAppWidgetInfo());
-                    // At this point #onCreateView should have been called, which in turn returned
-                    // the deferred view. There's no reason to keep the reference anymore, so we
-                    // removed it here.
-                    mDeferredViews.remove(appWidgetId);
-                }
+            if (view instanceof PendingAppWidgetHostView pv) {
+                pv.reInflate();
             }
         }
     }
@@ -173,34 +164,6 @@
     public void deleteAppWidgetId(int appWidgetId) {
         mWidgetHost.deleteAppWidgetId(appWidgetId);
         mViews.remove(appWidgetId);
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            final LauncherAppState state = LauncherAppState.getInstance(mContext);
-            synchronized (state.mCachedRemoteViews) {
-                state.mCachedRemoteViews.delete(appWidgetId);
-            }
-        }
-    }
-
-    /**
-     * Add the pending view to the host for complete configuration in further steps
-     * @param appWidgetId The ID of the specified app widget
-     * @param view The {@link PendingAppWidgetHostView} of the app widget
-     */
-    public void addPendingView(int appWidgetId, @NonNull PendingAppWidgetHostView view) {
-        mPendingViews.put(appWidgetId, view);
-    }
-
-    /**
-     * @param appWidgetId The app widget id of the specified widget
-     * @return The {@link PendingAppWidgetHostView} of the widget if it exists, null otherwise
-     */
-    @Nullable
-    protected PendingAppWidgetHostView getPendingView(int appWidgetId) {
-        return mPendingViews.get(appWidgetId);
-    }
-
-    protected void removePendingView(int appWidgetId) {
-        mPendingViews.remove(appWidgetId);
     }
 
     /**
@@ -214,7 +177,7 @@
      * @return The allocated app widget id if allocation is successful, returns -1 otherwise
      */
     public int allocateAppWidgetId() {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return AppWidgetManager.INVALID_APPWIDGET_ID;
         }
 
@@ -225,18 +188,18 @@
      * Add a listener that is triggered when the providers of the widgets are changed
      * @param listener The listener that notifies when the providers changed
      */
-    public void addProviderChangeListener(@NonNull ProviderChangedListener listener) {
-        LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
-        tempHost.addProviderChangeListener(listener);
+    public void addProviderChangeListener(
+            @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
+        MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.add(listener));
     }
 
     /**
      * Remove the specified listener from the host
      * @param listener The listener that is to be removed from the host
      */
-    public void removeProviderChangeListener(ProviderChangedListener listener) {
-        LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
-        tempHost.removeProviderChangeListener(listener);
+    public void removeProviderChangeListener(
+            LauncherWidgetHolder.ProviderChangedListener listener) {
+        MAIN_EXECUTOR.execute(() -> mProviderChangedListeners.remove(listener));
     }
 
     /**
@@ -247,7 +210,7 @@
      */
     public void startConfigActivity(@NonNull BaseDraggingActivity activity, int widgetId,
             int requestCode) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             sendActionCancelled(activity, requestCode);
             return;
         }
@@ -298,7 +261,7 @@
      */
     public void startBindFlow(@NonNull BaseActivity activity,
             int appWidgetId, @NonNull AppWidgetProviderInfo info, int requestCode) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             sendActionCancelled(activity, requestCode);
             return;
         }
@@ -316,20 +279,9 @@
      * Stop the host from listening to the widget updates
      */
     public void stopListening() {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return;
         }
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            // Cache the content from the widgets when Launcher stops listening to widget updates
-            final LauncherAppState state = LauncherAppState.getInstance(mContext);
-            synchronized (state.mCachedRemoteViews) {
-                for (int i = 0; i < mViews.size(); i++) {
-                    final int appWidgetId = mViews.keyAt(i);
-                    final LauncherAppWidgetHostView view = mViews.get(appWidgetId);
-                    state.mCachedRemoteViews.put(appWidgetId, view.mLastRemoteViews);
-                }
-            }
-        }
         mWidgetHost.stopListening();
         setListeningFlag(false);
     }
@@ -351,47 +303,114 @@
     }
 
     /**
-     * Create a view for the specified app widget
-     * @param context The activity context for which the view is created
+     * Adds a callback to be run everytime the provided app widget updates.
+     * @return a closable to remove this callback
+     */
+    public SafeCloseable addOnUpdateListener(
+            int appWidgetId, LauncherAppWidgetProviderInfo appWidget, Runnable callback) {
+        if (createView(appWidgetId, appWidget) instanceof ListenableHostView lhv) {
+            return lhv.addUpdateListener(callback);
+        }
+        return () -> { };
+    }
+
+    /**
+     * Create a view for the specified app widget. When calling this method from a background
+     * thread, the returned view will not receive ongoing updates. The caller needs to reattach
+     * the view using {@link #attachViewToHostAndGetAttachedView} on UIThread
+     *
      * @param appWidgetId The ID of the widget
-     * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
+     * @param appWidget   The {@link LauncherAppWidgetProviderInfo} of the widget
      * @return A view for the widget
      */
     @NonNull
-    public AppWidgetHostView createView(@NonNull Context context, int appWidgetId,
-            @NonNull LauncherAppWidgetProviderInfo appWidget) {
+    public AppWidgetHostView createView(
+            int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
         if (appWidget.isCustomWidget()) {
-            LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(context);
+            LauncherAppWidgetHostView lahv = new LauncherAppWidgetHostView(mContext);
             lahv.setAppWidget(0, appWidget);
-            CustomWidgetManager.INSTANCE.get(context).onViewCreated(lahv);
+            CustomWidgetManager.INSTANCE.get(mContext).onViewCreated(lahv);
             return lahv;
-        } else if ((mFlags & FLAG_LISTENING) == 0) {
-            // Since the launcher hasn't started listening to widget updates, we can't simply call
-            // super.createView here because the later will make a binder call to retrieve
-            // RemoteViews from system process.
-            // TODO: have launcher always listens to widget updates in background so that this
-            //  check can be removed altogether.
-            if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-                final RemoteViews cachedRemoteViews = getCachedRemoteViews(appWidgetId);
-                if (cachedRemoteViews != null) {
-                    // We've found RemoteViews from cache for this widget, so we will instantiate a
-                    // widget host view and populate it with the cached RemoteViews.
-                    final LauncherAppWidgetHostView view = new LauncherAppWidgetHostView(context);
-                    view.setAppWidget(appWidgetId, appWidget);
-                    view.updateAppWidget(cachedRemoteViews);
-                    mDeferredViews.put(appWidgetId, view);
-                    mViews.put(appWidgetId, view);
-                    return view;
-                }
-            }
-            // If cache misses or not enabled, a placeholder for the widget will be returned.
-            DeferredAppWidgetHostView view = new DeferredAppWidgetHostView(context);
-            view.setAppWidget(appWidgetId, appWidget);
+        }
+
+        LauncherAppWidgetHostView view = createViewInternal(appWidgetId, appWidget);
+        // Do not update mViews on a background thread call, as the holder is not thread safe.
+        if (!enableWorkspaceInflation() || Looper.myLooper() == Looper.getMainLooper()) {
             mViews.put(appWidgetId, view);
-            return view;
+        }
+        return view;
+    }
+
+    /**
+     * Attaches an already inflated view to the host. If the view can't be attached, creates
+     * and attaches a new view.
+     * @return the final attached view
+     */
+    @NonNull
+    public final AppWidgetHostView attachViewToHostAndGetAttachedView(
+            @NonNull LauncherAppWidgetHostView view) {
+
+        // Binder can also inflate placeholder widgets in case of backup-restore. Skip
+        // attaching such widgets
+        boolean isRealWidget = ((view instanceof PendingAppWidgetHostView pw)
+                ? pw.isDeferredWidget() : true)
+                && view.getAppWidgetInfo() != null;
+        if (isRealWidget && mViews.get(view.getAppWidgetId()) != view) {
+            view = recycleExistingView(view);
+            mViews.put(view.getAppWidgetId(), view);
+        }
+        return view;
+    }
+
+    /**
+     * Recycling logic:
+     *   1) If the final view should be a pendingView
+     *          if the provided view is also a pendingView, return itself
+     *          otherwise discard provided view and return a new pending view
+     *   2) If the recycled view is a pendingView, discard it and return a new view
+     *   3) Use the same for as creating a new view, but used the provided view in the host instead
+     *      of creating a new view. This ensures that all the host callbacks are properly attached
+     *      as a result of using the same flow.
+     */
+    protected LauncherAppWidgetHostView recycleExistingView(LauncherAppWidgetHostView view) {
+        if ((mFlags & FLAG_LISTENING) == 0) {
+            if (view instanceof PendingAppWidgetHostView pv && pv.isDeferredWidget()) {
+                return view;
+            } else {
+                return new PendingAppWidgetHostView(mContext, this, view.getAppWidgetId(),
+                        fromProviderInfo(mContext, view.getAppWidgetInfo()));
+            }
+        }
+        LauncherAppWidgetHost host = (LauncherAppWidgetHost) mWidgetHost;
+        if (view instanceof ListenableHostView lhv) {
+            host.recycleViewForNextCreation(lhv);
+        }
+
+        view = createViewInternal(
+                view.getAppWidgetId(), fromProviderInfo(mContext, view.getAppWidgetInfo()));
+        host.recycleViewForNextCreation(null);
+        return view;
+    }
+
+    @NonNull
+    protected LauncherAppWidgetHostView createViewInternal(
+            int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+        if ((mFlags & FLAG_LISTENING) == 0) {
+            // Since the launcher hasn't started listening to widget updates, we can't simply call
+            // host.createView here because the later will make a binder call to retrieve
+            // RemoteViews from system process.
+            return new PendingAppWidgetHostView(mContext, this, appWidgetId, appWidget);
         } else {
+            if (enableWorkspaceInflation() && Looper.myLooper() != Looper.getMainLooper()) {
+                // Widget is being inflated a background thread, just create and
+                // return a placeholder view
+                ListenableHostView hostView = new ListenableHostView(mContext);
+                hostView.setAppWidget(appWidgetId, appWidget);
+                return hostView;
+            }
             try {
-                return mWidgetHost.createView(context, appWidgetId, appWidget);
+                return (LauncherAppWidgetHostView) mWidgetHost.createView(
+                        mContext, appWidgetId, appWidget);
             } catch (Exception e) {
                 if (!Utilities.isBinderSizeError(e)) {
                     throw new RuntimeException(e);
@@ -402,7 +421,7 @@
                 // will update.
                 LauncherAppWidgetHostView view = mViews.get(appWidgetId);
                 if (view == null) {
-                    view = onCreateView(mContext, appWidgetId, appWidget);
+                    view = new ListenableHostView(mContext);
                 }
                 view.setAppWidget(appWidgetId, appWidget);
                 view.switchToErrorView();
@@ -422,45 +441,22 @@
     }
 
     /**
-     * Called to return a proper view when creating a view
-     * @param context The context for which the widget view is created
-     * @param appWidgetId The ID of the added widget
-     * @param appWidget The provider info of the added widget
-     * @return A view for the specified app widget
-     */
-    @NonNull
-    public LauncherAppWidgetHostView onCreateView(Context context, int appWidgetId,
-            AppWidgetProviderInfo appWidget) {
-        final LauncherAppWidgetHostView view;
-        if (getPendingView(appWidgetId) != null) {
-            view = getPendingView(appWidgetId);
-            removePendingView(appWidgetId);
-        } else if (mDeferredViews.get(appWidgetId) != null) {
-            // In case the widget view is deferred, we will simply return the deferred view as
-            // opposed to instantiate a new instance of LauncherAppWidgetHostView since launcher
-            // already added the former to the workspace.
-            view = mDeferredViews.get(appWidgetId);
-        } else {
-            view = new LauncherAppWidgetHostView(context);
-        }
-        mViews.put(appWidgetId, view);
-        return view;
-    }
-
-    /**
      * Clears all the views from the host
      */
     public void clearViews() {
         LauncherAppWidgetHost tempHost = (LauncherAppWidgetHost) mWidgetHost;
         tempHost.clearViews();
-        if (FeatureFlags.ENABLE_CACHED_WIDGET.get()) {
-            // Clear previously cached content from existing widgets
-            mDeferredViews.clear();
-        }
         mViews.clear();
     }
 
     /**
+     * Clears all the internal widget views
+     */
+    public void clearWidgetViews() {
+        clearViews();
+    }
+
+    /**
      * @return True if the host is listening to the updates, false otherwise
      */
     public boolean isListening() {
@@ -496,14 +492,6 @@
         return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
     }
 
-    @Nullable
-    private RemoteViews getCachedRemoteViews(int appWidgetId) {
-        final LauncherAppState state = LauncherAppState.getInstance(mContext);
-        synchronized (state.mCachedRemoteViews) {
-            return state.mCachedRemoteViews.get(appWidgetId);
-        }
-    }
-
     /**
      * Returns the new LauncherWidgetHolder instance
      */
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index ccf4b2e..a916252 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -25,8 +25,9 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 /**
@@ -42,6 +43,16 @@
     public Bundle bindOptions = null;
     public int sourceContainer;
 
+    public WidgetRecommendationCategory recommendationCategory = null;
+
+    public PendingAddWidgetInfo(
+            LauncherAppWidgetProviderInfo i,
+            int container,
+            WidgetRecommendationCategory recommendationCategory) {
+        this(i, container);
+        this.recommendationCategory = recommendationCategory;
+    }
+
     public PendingAddWidgetInfo(LauncherAppWidgetProviderInfo i, int container) {
         if (i.isCustomWidget()) {
             itemType = LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
@@ -71,8 +82,8 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
-        LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+        LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
         return info.toBuilder()
                 .addItemAttributes(LauncherAppWidgetInfo.getAttribute(sourceContainer))
                 .build();
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 1c88c4a..9c9b80d 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -16,19 +16,31 @@
 
 package com.android.launcher3.widget;
 
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
 import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
+import android.text.TextUtils;
 import android.util.SizeF;
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
@@ -36,17 +48,19 @@
 import android.view.View.OnClickListener;
 import android.widget.RemoteViews;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.FastBitmapDrawable;
-import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.Themes;
 
 import java.util.List;
@@ -54,55 +68,189 @@
 public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
         implements OnClickListener, ItemInfoUpdateReceiver {
     private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
-    private static final float MIN_SATUNATION = 0.7f;
+    private static final float MIN_SATURATION = 0.7f;
+
+    private static final int FLAG_DRAW_SETTINGS = 1;
+    private static final int FLAG_DRAW_ICON = 2;
+    private static final int FLAG_DRAW_LABEL = 4;
+
+    private static final int DEFERRED_ALPHA = 0x77;
 
     private final Rect mRect = new Rect();
-    private OnClickListener mClickListener;
+
+    private final Matrix mMatrix = new Matrix();
+    private final RectF mPreviewBitmapRect = new RectF();
+    private final RectF mCanvasRect = new RectF();
+
+    private final LauncherWidgetHolder mWidgetHolder;
+    private final LauncherAppWidgetProviderInfo mAppwidget;
     private final LauncherAppWidgetInfo mInfo;
     private final int mStartState;
     private final boolean mDisabledForSafeMode;
+    private final CharSequence mLabel;
+
+    private OnClickListener mClickListener;
+    private SafeCloseable mOnDetachCleanup;
+
+    private int mDragFlags;
 
     private Drawable mCenterDrawable;
     private Drawable mSettingIconDrawable;
 
     private boolean mDrawableSizeChanged;
+    private boolean mIsDeferredWidget;
 
     private final TextPaint mPaint;
+
+    private final Paint mPreviewPaint;
     private Layout mSetupTextLayout;
 
-    public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
-            IconCache cache, boolean disabledForSafeMode) {
-        super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
+    @Nullable private Bitmap mPreviewBitmap;
 
-        mInfo = info;
-        mStartState = info.restoreStatus;
-        mDisabledForSafeMode = disabledForSafeMode;
+    public PendingAppWidgetHostView(Context context, LauncherWidgetHolder widgetHolder,
+            LauncherAppWidgetInfo info, @Nullable LauncherAppWidgetProviderInfo appWidget) {
+        this(context, widgetHolder, info, appWidget, null);
+    }
 
-        mPaint = new TextPaint();
-        mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
-        mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
-                mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
-        setBackgroundResource(R.drawable.pending_widget_bg);
-        setWillNotDraw(false);
-
+    public PendingAppWidgetHostView(Context context, LauncherWidgetHolder widgetHolder,
+            LauncherAppWidgetInfo info, @Nullable LauncherAppWidgetProviderInfo appWidget,
+            @Nullable Bitmap previewBitmap) {
+        this(context, widgetHolder, info, appWidget,
+                context.getResources().getText(R.string.gadget_complete_setup_text), previewBitmap);
         super.updateAppWidget(null);
-        setOnClickListener(mLauncher.getItemOnClickListener());
+        setOnClickListener(mActivityContext.getItemOnClickListener());
 
         if (info.pendingItemInfo == null) {
             info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName(),
                     info.user);
-            cache.updateIconInBackground(this, info.pendingItemInfo);
+            LauncherAppState.getInstance(context).getIconCache()
+                    .updateIconInBackground(this, info.pendingItemInfo);
         } else {
             reapplyItemInfo(info.pendingItemInfo);
         }
     }
 
+    public PendingAppWidgetHostView(
+            Context context, LauncherWidgetHolder widgetHolder,
+            int appWidgetId, @NonNull LauncherAppWidgetProviderInfo appWidget) {
+        this(context, widgetHolder, new LauncherAppWidgetInfo(appWidgetId, appWidget.provider),
+                appWidget, appWidget.label, null);
+        getBackground().mutate().setAlpha(DEFERRED_ALPHA);
+
+        mCenterDrawable = new ColorDrawable(Color.TRANSPARENT);
+        mDragFlags = FLAG_DRAW_LABEL;
+        mDrawableSizeChanged = true;
+        mIsDeferredWidget = true;
+    }
+
+    /**
+     * Set {@link Bitmap} of widget preview and update background drawable. When showing preview
+     * bitmap, we shouldn't draw background.
+     */
+    public void setPreviewBitmapAndUpdateBackground(@Nullable Bitmap previewBitmap) {
+        setBackgroundResource(previewBitmap != null ? 0 : R.drawable.pending_widget_bg);
+        if (this.mPreviewBitmap == previewBitmap) {
+            return;
+        }
+        this.mPreviewBitmap = previewBitmap;
+        invalidate();
+    }
+
+    private PendingAppWidgetHostView(Context context,
+            LauncherWidgetHolder widgetHolder, LauncherAppWidgetInfo info,
+            LauncherAppWidgetProviderInfo appwidget, CharSequence label,
+            @Nullable Bitmap previewBitmap) {
+        super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
+        mWidgetHolder = widgetHolder;
+        mAppwidget = appwidget;
+        mInfo = info;
+        mStartState = info.restoreStatus;
+        mDisabledForSafeMode = LauncherAppState.getInstance(context).isSafeModeEnabled();
+        mLabel = label;
+
+        mPaint = new TextPaint();
+        mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
+        mPaint.setTextSize(TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_PX,
+                mActivityContext.getDeviceProfile().iconTextSizePx,
+                getResources().getDisplayMetrics()));
+        mPreviewPaint = new Paint(ANTI_ALIAS_FLAG | DITHER_FLAG | FILTER_BITMAP_FLAG);
+
+        setWillNotDraw(false);
+        setPreviewBitmapAndUpdateBackground(previewBitmap);
+    }
+
+    @Override
+    public AppWidgetProviderInfo getAppWidgetInfo() {
+        return mAppwidget;
+    }
+
+    @Override
+    public int getAppWidgetId() {
+        return mInfo.appWidgetId;
+    }
+
     @Override
     public void updateAppWidget(RemoteViews remoteViews) {
+        checkIfRestored();
+    }
+
+    private void checkIfRestored() {
         WidgetManagerHelper widgetManagerHelper = new WidgetManagerHelper(getContext());
         if (widgetManagerHelper.isAppWidgetRestored(mInfo.appWidgetId)) {
-            super.updateAppWidget(remoteViews);
-            reInflate();
+            MAIN_EXECUTOR.getHandler().post(this::reInflate);
+        }
+    }
+
+    public boolean isDeferredWidget() {
+        return mIsDeferredWidget;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+
+        if ((mAppwidget != null)
+                && !mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
+                && mInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+            // If the widget is not completely restored, but has a valid ID, then listen of
+            // updates from provider app for potential restore complete.
+            if (mOnDetachCleanup != null) {
+                mOnDetachCleanup.close();
+            }
+            mOnDetachCleanup = mWidgetHolder.addOnUpdateListener(
+                    mInfo.appWidgetId, mAppwidget, this::checkIfRestored);
+            checkIfRestored();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mOnDetachCleanup != null) {
+            mOnDetachCleanup.close();
+            mOnDetachCleanup = null;
+        }
+    }
+
+    /**
+     * Forces the Launcher to reinflate the widget view
+     */
+    public void reInflate() {
+        if (!isAttachedToWindow()) {
+            return;
+        }
+        LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+        if (info == null) {
+            // This occurs when LauncherAppWidgetHostView is used to render a preview layout.
+            return;
+        }
+        if (mActivityContext instanceof Launcher launcher) {
+            // Remove and rebind the current widget (which was inflated in the wrong
+            // orientation), but don't delete it from the database
+            launcher.removeItem(this, info, false  /* deleteFromDb */,
+                    "widget removed because of configuration change");
+            launcher.bindAppWidget(info);
         }
     }
 
@@ -147,7 +295,10 @@
             mCenterDrawable.setCallback(null);
             mCenterDrawable = null;
         }
+        mDragFlags = 0;
         if (info.bitmap.icon != null) {
+            mDragFlags = FLAG_DRAW_ICON;
+
             Drawable widgetCategoryIcon = getWidgetCategoryIcon();
             // The view displays three modes,
             //   1) App icon in the center
@@ -169,6 +320,8 @@
                         : widgetCategoryIcon;
                 mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
                 updateSettingColor(info.bitmap.color);
+
+                mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
             } else {
                 mCenterDrawable = widgetCategoryIcon == null
                         ? newPendingIcon(getContext(), info)
@@ -186,7 +339,7 @@
         // Make the dominant color bright.
         float[] hsv = new float[3];
         Color.colorToHSV(dominantColor, hsv);
-        hsv[1] = Math.min(hsv[1], MIN_SATUNATION);
+        hsv[1] = Math.min(hsv[1], MIN_SATURATION);
         hsv[2] = 1;
         mSettingIconDrawable.setColorFilter(Color.HSVToColor(hsv),  PorterDuff.Mode.SRC_IN);
     }
@@ -227,7 +380,7 @@
     }
 
     private void updateDrawableBounds() {
-        DeviceProfile grid = mLauncher.getDeviceProfile();
+        DeviceProfile grid = mActivityContext.getDeviceProfile();
         int paddingTop = getPaddingTop();
         int paddingBottom = getPaddingBottom();
         int paddingLeft = getPaddingLeft();
@@ -239,73 +392,77 @@
         int availableWidth = getWidth() - paddingLeft - paddingRight - 2 * minPadding;
         int availableHeight = getHeight() - paddingTop - paddingBottom - 2 * minPadding;
 
-        if (mSettingIconDrawable == null) {
-            int maxSize = grid.iconSizePx;
-            int size = Math.min(maxSize, Math.min(availableWidth, availableHeight));
+        float iconSize = ((mDragFlags & FLAG_DRAW_ICON) == 0) ? 0
+                : Math.max(0, Math.min(availableWidth, availableHeight));
+        // Use twice the setting size factor, as the setting is drawn at a corner and the
+        // icon is drawn in the center.
+        float settingIconScaleFactor = ((mDragFlags & FLAG_DRAW_SETTINGS) == 0) ? 0
+                : 1 + SETUP_ICON_SIZE_FACTOR * 2;
 
-            mRect.set(0, 0, size, size);
-            mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2);
-            mCenterDrawable.setBounds(mRect);
-        } else  {
-            float iconSize = Math.max(0, Math.min(availableWidth, availableHeight));
+        int maxSize = Math.max(availableWidth, availableHeight);
+        if (iconSize * settingIconScaleFactor > maxSize) {
+            // There is an overlap
+            iconSize = maxSize / settingIconScaleFactor;
+        }
 
-            // Use twice the setting size factor, as the setting is drawn at a corner and the
-            // icon is drawn in the center.
-            float settingIconScaleFactor = 1 + SETUP_ICON_SIZE_FACTOR * 2;
-            int maxSize = Math.max(availableWidth, availableHeight);
-            if (iconSize * settingIconScaleFactor > maxSize) {
-                // There is an overlap
-                iconSize = maxSize / settingIconScaleFactor;
+        int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx);
+
+        // Icon top when we do not draw the text
+        int iconTop = (getHeight() - actualIconSize) / 2;
+        mSetupTextLayout = null;
+
+        if (availableWidth > 0 && !TextUtils.isEmpty(mLabel)
+                && ((mDragFlags & FLAG_DRAW_LABEL) != 0)) {
+            // Recreate the setup text.
+            mSetupTextLayout = new StaticLayout(
+                    mLabel, mPaint, availableWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+            int textHeight = mSetupTextLayout.getHeight();
+
+            // Extra icon size due to the setting icon
+            float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor
+                    + grid.iconDrawablePaddingPx;
+
+            if (minHeightWithText < availableHeight) {
+                // We can draw the text as well
+                iconTop = (getHeight() - textHeight
+                        - grid.iconDrawablePaddingPx - actualIconSize) / 2;
+
+            } else {
+                // We can't draw the text. Let the iconTop be same as before.
+                mSetupTextLayout = null;
             }
+        }
 
-            int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx);
+        mRect.set(0, 0, actualIconSize, actualIconSize);
+        mRect.offset((getWidth() - actualIconSize) / 2, iconTop);
+        mCenterDrawable.setBounds(mRect);
 
-            // Icon top when we do not draw the text
-            int iconTop = (getHeight() - actualIconSize) / 2;
-            mSetupTextLayout = null;
-
-            if (availableWidth > 0) {
-                // Recreate the setup text.
-                mSetupTextLayout = new StaticLayout(
-                        getResources().getText(R.string.gadget_complete_setup_text), mPaint,
-                        availableWidth, Layout.Alignment.ALIGN_CENTER, 1, 0, true);
-                int textHeight = mSetupTextLayout.getHeight();
-
-                // Extra icon size due to the setting icon
-                float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor
-                        + grid.iconDrawablePaddingPx;
-
-                if (minHeightWithText < availableHeight) {
-                    // We can draw the text as well
-                    iconTop = (getHeight() - textHeight -
-                            grid.iconDrawablePaddingPx - actualIconSize) / 2;
-
-                } else {
-                    // We can't draw the text. Let the iconTop be same as before.
-                    mSetupTextLayout = null;
-                }
-            }
-
-            mRect.set(0, 0, actualIconSize, actualIconSize);
-            mRect.offset((getWidth() - actualIconSize) / 2, iconTop);
-            mCenterDrawable.setBounds(mRect);
-
+        if (mSettingIconDrawable != null) {
             mRect.left = paddingLeft + minPadding;
             mRect.right = mRect.left + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
             mRect.top = paddingTop + minPadding;
             mRect.bottom = mRect.top + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize);
             mSettingIconDrawable.setBounds(mRect);
+        }
 
-            if (mSetupTextLayout != null) {
-                // Set up position for dragging the text
-                mRect.left = paddingLeft + minPadding;
-                mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx;
-            }
+        if (mSetupTextLayout != null) {
+            // Set up position for dragging the text
+            mRect.left = paddingLeft + minPadding;
+            mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx;
         }
     }
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if (mPreviewBitmap != null
+                && (mInfo.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0) {
+            mPreviewBitmapRect.set(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
+            mCanvasRect.set(0, 0, getWidth(), getHeight());
+
+            mMatrix.setRectToRect(mPreviewBitmapRect, mCanvasRect, Matrix.ScaleToFit.CENTER);
+            canvas.drawBitmap(mPreviewBitmap, mMatrix, mPreviewPaint);
+            return;
+        }
         if (mCenterDrawable == null) {
             // Nothing to draw
             return;
@@ -326,7 +483,6 @@
             mSetupTextLayout.draw(canvas);
             canvas.restore();
         }
-
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index c30342a..ea167d7 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3.widget;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+
+import static com.android.launcher3.Flags.enableWidgetTapToAdd;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
 import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
 import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
@@ -23,7 +26,6 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.os.Process;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -34,8 +36,8 @@
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
@@ -44,13 +46,19 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.RoundDrawableWrapper;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
+import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.function.Consumer;
 
@@ -69,25 +77,27 @@
     private static final boolean DEBUG = false;
 
     private static final int FADE_IN_DURATION_MS = 90;
+    private static final int ADD_BUTTON_FADE_DURATION_MS = 300;
 
     /**
      * The requested scale of the preview container. It can be lower than this as well.
      */
     private float mPreviewContainerScale = 1f;
-
+    private Size mPreviewContainerSize = new Size(0, 0);
     private FrameLayout mWidgetImageContainer;
     private WidgetImageView mWidgetImage;
-    private ImageView mWidgetBadge;
     private TextView mWidgetName;
     private TextView mWidgetDims;
     private TextView mWidgetDescription;
+    private Button mWidgetAddButton;
+    private LinearLayout mWidgetTextContainer;
 
     private WidgetItem mItem;
     private Size mWidgetSize;
 
     private final DatabaseWidgetPreviewLoader mWidgetPreviewLoader;
 
-    protected HandlerRunnable mActiveRequest;
+    protected CancellableTask mActiveRequest;
     private boolean mAnimatePreview = true;
 
     protected final ActivityContext mActivity;
@@ -99,6 +109,9 @@
     private float mAppWidgetHostViewScale = 1f;
     private int mSourceContainer = CONTAINER_WIDGETS_TRAY;
 
+    private CancellableTask mIconLoadRequest;
+    private boolean mIsShowingAddButton = false;
+
     public WidgetCell(Context context) {
         this(context, null);
     }
@@ -127,10 +140,14 @@
 
         mWidgetImageContainer = findViewById(R.id.widget_preview_container);
         mWidgetImage = findViewById(R.id.widget_preview);
-        mWidgetBadge = findViewById(R.id.widget_badge);
         mWidgetName = findViewById(R.id.widget_name);
         mWidgetDims = findViewById(R.id.widget_dims);
         mWidgetDescription = findViewById(R.id.widget_description);
+        mWidgetTextContainer = findViewById(R.id.widget_text_container);
+        mWidgetAddButton = findViewById(R.id.widget_add_button);
+        if (enableWidgetTapToAdd()) {
+            mWidgetAddButton.setVisibility(INVISIBLE);
+        }
     }
 
     public void setRemoteViewsPreview(RemoteViews view) {
@@ -147,6 +164,11 @@
         return mAppWidgetHostViewScale;
     }
 
+    /** Returns the {@link WidgetItem} for this {@link WidgetCell}. */
+    public WidgetItem getWidgetItem() {
+        return mItem;
+    }
+
     /**
      * Called to clear the view and free attached resources. (e.g., {@link Bitmap}
      */
@@ -157,12 +179,16 @@
         mWidgetImage.animate().cancel();
         mWidgetImage.setDrawable(null);
         mWidgetImage.setVisibility(View.VISIBLE);
-        mWidgetBadge.setImageDrawable(null);
-        mWidgetBadge.setVisibility(View.GONE);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
         mWidgetDescription.setText(null);
         mWidgetDescription.setVisibility(GONE);
+        showDescription(true);
+        showDimensions(true);
+
+        if (enableWidgetTapToAdd()) {
+            hideAddButton(/* animate= */ false);
+        }
 
         if (mActiveRequest != null) {
             mActiveRequest.cancel();
@@ -173,10 +199,12 @@
             mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
         }
         mAppWidgetHostViewPreview = null;
+        mPreviewContainerSize = new Size(0, 0);
         mAppWidgetHostViewScale = 1f;
         mPreviewContainerScale = 1f;
         mItem = null;
         mWidgetSize = new Size(0, 0);
+        showAppIconInWidgetTitle(false);
     }
 
     public void setSourceContainer(int sourceContainer) {
@@ -187,38 +215,25 @@
      * Applies the item to this view
      */
     public void applyFromCellItem(WidgetItem item) {
-        applyFromCellItem(item, 1f);
-    }
-
-    /**
-     * Applies the item to this view
-     */
-    public void applyFromCellItem(WidgetItem item, float previewScale) {
-        applyFromCellItem(item, previewScale, this::applyPreview, null);
+        applyFromCellItem(item, this::applyPreview, /*cachedPreview=*/null);
     }
 
     /**
      * Applies the item to this view
      * @param item item to apply
-     * @param previewScale factor to scale the preview
      * @param callback callback when preview is loaded in case the preview is being loaded or cached
      * @param cachedPreview previously cached preview bitmap is present
      */
-    public void applyFromCellItem(WidgetItem item, float previewScale,
-            @NonNull Consumer<Bitmap> callback, @Nullable Bitmap cachedPreview) {
-        mPreviewContainerScale = previewScale;
-
+    public void applyFromCellItem(WidgetItem item, @NonNull Consumer<Bitmap> callback,
+            @Nullable Bitmap cachedPreview) {
         Context context = getContext();
         mItem = item;
         mWidgetSize = getWidgetItemSizePx(getContext(), mActivity.getDeviceProfile(), mItem);
+        initPreviewContainerSizeAndScale();
 
         mWidgetName.setText(mItem.label);
-        mWidgetName.setContentDescription(
-                context.getString(R.string.widget_preview_context_description, mItem.label));
         mWidgetDims.setText(context.getString(R.string.widget_dims_format,
                 mItem.spanX, mItem.spanY));
-        mWidgetDims.setContentDescription(context.getString(
-                R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
         if (!TextUtils.isEmpty(mItem.description)) {
             mWidgetDescription.setText(mItem.description);
             mWidgetDescription.setVisibility(VISIBLE);
@@ -226,6 +241,14 @@
             mWidgetDescription.setVisibility(GONE);
         }
 
+        // Setting the content description on the WidgetCell itself ensures that it remains
+        // screen reader focusable when the add button is showing and the text is hidden.
+        setContentDescription(createContentDescription(context));
+        if (mWidgetAddButton != null) {
+            mWidgetAddButton.setContentDescription(context.getString(
+                    R.string.widget_add_button_content_description, mItem.label));
+        }
+
         if (item.activityInfo != null) {
             setTag(new PendingAddShortcutInfo(item.activityInfo));
         } else {
@@ -236,6 +259,11 @@
             mAppWidgetHostViewPreview = createAppWidgetHostView(context);
             setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
                     mRemoteViewsPreview);
+        } else if (Flags.enableGeneratedPreviews()
+                && item.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)) {
+            mAppWidgetHostViewPreview = createAppWidgetHostView(context);
+            setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
+                    item.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN));
         } else if (item.hasPreviewLayout()) {
             // If the context is a Launcher activity, DragView will show mAppWidgetHostViewPreview
             // as a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView,
@@ -259,6 +287,27 @@
         }
     }
 
+    private void initPreviewContainerSizeAndScale() {
+        WidgetPreviewContainerSize previewSize = WidgetPreviewContainerSize.Companion.forItem(mItem,
+                mActivity.getDeviceProfile());
+        mPreviewContainerSize = WidgetSizes.getWidgetSizePx(mActivity.getDeviceProfile(),
+                previewSize.spanX, previewSize.spanY);
+
+        float scaleX = (float) mPreviewContainerSize.getWidth() / mWidgetSize.getWidth();
+        float scaleY = (float) mPreviewContainerSize.getHeight() / mWidgetSize.getHeight();
+        mPreviewContainerScale = Math.min(scaleX, scaleY);
+    }
+
+    private String createContentDescription(Context context) {
+        String contentDescription =
+                context.getString(R.string.widget_preview_name_and_dims_content_description,
+                        mItem.label, mItem.spanX, mItem.spanY);
+        if (!TextUtils.isEmpty(mItem.description)) {
+            contentDescription += " " + mItem.description;
+        }
+        return contentDescription;
+    }
+
     private void setAppWidgetHostViewPreview(
             NavigableAppWidgetHostView appWidgetHostViewPreview,
             LauncherAppWidgetProviderInfo providerInfo,
@@ -343,14 +392,48 @@
         }
     }
 
-    /** Used to show the badge when the widget is in the recommended section
+    /**
+     * Shows or hides the long description displayed below each widget.
+     *
+     * @param show a flag that shows the long description of the widget if {@code true}, hides it if
+     *             {@code false}.
      */
-    public void showBadge() {
-        if (Process.myUserHandle().equals(mItem.user)) {
-            mWidgetBadge.setVisibility(View.GONE);
+    public void showDescription(boolean show) {
+        mWidgetDescription.setVisibility(show ? VISIBLE : GONE);
+    }
+
+    /**
+     * Shows or hides the dimensions displayed below each widget.
+     *
+     * @param show a flag that shows the dimensions of the widget if {@code true}, hides it if
+     *             {@code false}.
+     */
+    public void showDimensions(boolean show) {
+        mWidgetDims.setVisibility(show ? VISIBLE : GONE);
+    }
+
+    /**
+     * Set whether the app icon, for the app that provides the widget, should be shown next to the
+     * title text of the widget.
+     *
+     * @param show true if the app icon should be shown in the title text of the cell, false hides
+     *             it.
+     */
+    public void showAppIconInWidgetTitle(boolean show) {
+        if (show) {
+            if (mItem.widgetInfo != null) {
+                loadHighResPackageIcon();
+
+                Drawable icon = mItem.bitmap.newIcon(getContext());
+                int size = getResources().getDimensionPixelSize(R.dimen.widget_cell_app_icon_size);
+                icon.setBounds(0, 0, size, size);
+                mWidgetName.setCompoundDrawablesRelative(
+                        icon,
+                        null, null, null);
+            }
         } else {
-            mWidgetBadge.setVisibility(View.VISIBLE);
-            mWidgetBadge.setImageResource(R.drawable.ic_work_app_badge);
+            cancelIconLoadRequest();
+            mWidgetName.setCompoundDrawables(null, null, null, null);
         }
     }
 
@@ -394,17 +477,117 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         ViewGroup.LayoutParams containerLp = mWidgetImageContainer.getLayoutParams();
-
-        mAppWidgetHostViewScale = mPreviewContainerScale;
         int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
-        containerLp.width = Math.round(mWidgetSize.getWidth() * mAppWidgetHostViewScale);
+
+        // mPreviewContainerScale ensures the needed scaling with respect to original widget size.
+        mAppWidgetHostViewScale = mPreviewContainerScale;
+        containerLp.width = mPreviewContainerSize.getWidth();
+        containerLp.height = mPreviewContainerSize.getHeight();
+
+        // If we don't have enough available width, scale the preview container to fit.
         if (containerLp.width > maxWidth) {
             containerLp.width = maxWidth;
-            mAppWidgetHostViewScale = (float) containerLp.width / mWidgetSize.getWidth();
+            mAppWidgetHostViewScale = (float) containerLp.width / mPreviewContainerSize.getWidth();
+            containerLp.height = Math.round(
+                    mPreviewContainerSize.getHeight() * mAppWidgetHostViewScale);
         }
-        containerLp.height = Math.round(mWidgetSize.getHeight() * mAppWidgetHostViewScale);
-        // No need to call mWidgetImageContainer.setLayoutParams as we are in measure pass
 
+        // No need to call mWidgetImageContainer.setLayoutParams as we are in measure pass
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
+
+    /**
+     * Loads a high resolution package icon to show next to the widget title.
+     */
+    public void loadHighResPackageIcon() {
+        cancelIconLoadRequest();
+        if (mItem.bitmap.isLowRes()) {
+            // We use the package icon instead of the receiver one so that the overall package that
+            // the widget came from can be identified in the recommended widgets. This matches with
+            // the package icon headings in the all widgets list.
+            PackageItemInfo tmpPackageItem = new PackageItemInfo(
+                    mItem.componentName.getPackageName(),
+                    mItem.user);
+            mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
+                    .updateIconInBackground(this::reapplyIconInfo, tmpPackageItem);
+        }
+    }
+
+    /** Can be called to update the package icon shown in the label of recommended widgets. */
+    private void reapplyIconInfo(ItemInfoWithIcon info) {
+        if (mItem == null || info.bitmap.isNullOrLowRes()) {
+            showAppIconInWidgetTitle(false);
+            return;
+        }
+        mItem.bitmap = info.bitmap;
+        showAppIconInWidgetTitle(true);
+    }
+
+    private void cancelIconLoadRequest() {
+        if (mIconLoadRequest != null) {
+            mIconLoadRequest.cancel();
+            mIconLoadRequest = null;
+        }
+    }
+
+    /**
+     * Show tap to add button.
+     * @param callback Callback to be set on the button.
+     */
+    public void showAddButton(View.OnClickListener callback) {
+        if (mIsShowingAddButton) return;
+        mIsShowingAddButton = true;
+
+        mWidgetAddButton.setAlpha(0F);
+        mWidgetAddButton.setVisibility(VISIBLE);
+        mWidgetAddButton.setOnClickListener(callback);
+        mWidgetAddButton.animate().cancel();
+        mWidgetAddButton.animate()
+                .alpha(1F)
+                .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+
+        mWidgetTextContainer.animate().cancel();
+        mWidgetTextContainer.animate()
+                .alpha(0F)
+                .setDuration(ADD_BUTTON_FADE_DURATION_MS)
+                .withEndAction(() -> {
+                    mWidgetTextContainer.setVisibility(INVISIBLE);
+                });
+    }
+
+    /**
+     * Hide tap to add button.
+     */
+    public void hideAddButton(boolean animate) {
+        if (!mIsShowingAddButton) return;
+        mIsShowingAddButton = false;
+
+        mWidgetAddButton.setOnClickListener(null);
+        mWidgetAddButton.animate().cancel();
+        mWidgetTextContainer.animate().cancel();
+
+        if (!animate) {
+            mWidgetAddButton.setVisibility(INVISIBLE);
+            mWidgetTextContainer.setVisibility(VISIBLE);
+            mWidgetTextContainer.setAlpha(1F);
+            return;
+        }
+
+        mWidgetAddButton.animate()
+                .alpha(0F)
+                .setDuration(ADD_BUTTON_FADE_DURATION_MS)
+                .withEndAction(() -> {
+                    mWidgetAddButton.setVisibility(INVISIBLE);
+                });
+
+        mWidgetTextContainer.setAlpha(0F);
+        mWidgetTextContainer.setVisibility(VISIBLE);
+        mWidgetTextContainer.animate()
+                .alpha(1F)
+                .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+    }
+
+    public boolean isShowingAddButton() {
+        return mIsShowingAddButton;
+    }
 }
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
index b18cd47..1cc00ef 100644
--- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -1,7 +1,6 @@
 package com.android.launcher3.widget;
 
 import android.appwidget.AppWidgetHostView;
-import android.content.Context;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.Log;
@@ -117,7 +116,7 @@
                     return;
                 }
                 AppWidgetHostView hostView = mLauncher.getAppWidgetHolder().createView(
-                        (Context) mLauncher, mWidgetLoadingId, pInfo);
+                        mWidgetLoadingId, pInfo);
                 mInfo.boundWidget = hostView;
 
                 // We used up the widget Id in binding the above view.
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index 11f4485..f332054 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -24,8 +24,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-import com.android.launcher3.R;
-
 /**
  * View that draws a bitmap horizontally centered. If the image width is greater than the view
  * width, the image is scaled down appropriately.
@@ -33,8 +31,6 @@
 public class WidgetImageView extends View {
 
     private final RectF mDstRectF = new RectF();
-    private final int mBadgeMargin;
-
     private Drawable mDrawable;
 
     public WidgetImageView(Context context) {
@@ -47,9 +43,6 @@
 
     public WidgetImageView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-
-        mBadgeMargin = context.getResources()
-                .getDimensionPixelSize(R.dimen.profile_badge_margin);
     }
 
     /** Set the drawable to use for this view. */
@@ -82,15 +75,27 @@
     private void updateDstRectF() {
         float myWidth = getWidth();
         float myHeight = getHeight();
-        float bitmapWidth = mDrawable.getIntrinsicWidth();
+        final float bitmapWidth = mDrawable.getIntrinsicWidth();
+        final float bitmapHeight = mDrawable.getIntrinsicHeight();
+        final float bitmapAspectRatio = bitmapWidth / bitmapHeight;
+        final float containerAspectRatio = myWidth / myHeight;
 
-        final float scale = bitmapWidth > myWidth ? myWidth / bitmapWidth : 1;
-        float scaledWidth = bitmapWidth * scale;
-        float scaledHeight = mDrawable.getIntrinsicHeight() * scale;
+        // Scale by width if image has larger aspect ratio than the container else by height; and
+        // avoid cropping the previews
+        final float scale = bitmapAspectRatio > containerAspectRatio ? myWidth / bitmapWidth
+                : myHeight / bitmapHeight;
 
-        mDstRectF.left = (myWidth - scaledWidth) / 2;
-        mDstRectF.right = (myWidth + scaledWidth) / 2;
+        final float scaledWidth = bitmapWidth * scale;
+        final float scaledHeight = bitmapHeight * scale;
 
+        // Avoid cropping by checking bounds after scaling.
+        if (scaledWidth > myWidth) {
+            mDstRectF.left = 0;
+            mDstRectF.right = scaledWidth;
+        } else {
+            mDstRectF.left = (myWidth - scaledWidth) / 2;
+            mDstRectF.right = (myWidth + scaledWidth) / 2;
+        }
         if (scaledHeight > myHeight) {
             mDstRectF.top = 0;
             mDstRectF.bottom = scaledHeight;
diff --git a/src/com/android/launcher3/widget/WidgetInflater.kt b/src/com/android/launcher3/widget/WidgetInflater.kt
new file mode 100644
index 0000000..271c9c2
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetInflater.kt
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget
+
+import 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.logging.FileLog
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.qsb.QsbContainerView
+
+/** Utility class for handling widget inflation taking into account all the restore state updates */
+class WidgetInflater(private val context: Context) {
+
+    private val widgetHelper = WidgetManagerHelper(context)
+
+    fun inflateAppWidget(
+        item: LauncherAppWidgetInfo,
+    ): InflationResult {
+        if (item.hasOptionFlag(LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET)) {
+            item.providerName = QsbContainerView.getSearchComponentName(context)
+            if (item.providerName == null) {
+                return InflationResult(
+                    TYPE_DELETE,
+                    reason = "search widget removed because search component cannot be found",
+                    restoreErrorType = RestoreError.NO_SEARCH_WIDGET
+                )
+            }
+        }
+        if (LauncherAppState.INSTANCE.get(context).isSafeModeEnabled) {
+            return InflationResult(TYPE_PENDING)
+        }
+        val appWidgetInfo: LauncherAppWidgetProviderInfo?
+        var removalReason = ""
+        @RestoreError var logReason = RestoreError.APP_NOT_INSTALLED
+        var update = false
+
+        if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+            // The widget id is not valid. Try to find the widget based on the provider info.
+            appWidgetInfo = widgetHelper.findProvider(item.providerName, item.user)
+            if (appWidgetInfo == null) {
+                if (!BuildConfig.WIDGETS_ENABLED) {
+                    removalReason = "widgets are disabled on go device."
+                    logReason = RestoreError.WIDGETS_DISABLED
+                } else {
+                    removalReason = "WidgetManagerHelper cannot find a provider from provider info."
+                    logReason = RestoreError.MISSING_WIDGET_PROVIDER
+                }
+            } else if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) {
+                // since appWidgetInfo is not null anymore, update the provider status
+                item.restoreStatus =
+                    item.restoreStatus and LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY.inv()
+                update = true
+            }
+        } else {
+            appWidgetInfo =
+                widgetHelper.getLauncherAppWidgetInfo(item.appWidgetId, item.targetComponent)
+            if (appWidgetInfo == null) {
+                if (item.appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
+                    removalReason = "CustomWidgetManager cannot find provider from that widget id."
+                    logReason = RestoreError.MISSING_INFO
+                } else {
+                    removalReason =
+                        ("AppWidgetManager cannot find provider for that widget id." +
+                            " It could be because AppWidgetService is not available, or the" +
+                            " appWidgetId has not been bound to a the provider yet, or you" +
+                            " don't have access to that appWidgetId.")
+                    logReason = RestoreError.INVALID_WIDGET_ID
+                }
+            }
+        }
+
+        // If the provider is ready, but the widget is not yet restored, try to restore it.
+        if (
+            !item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) &&
+                item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED
+        ) {
+            if (appWidgetInfo == null) {
+                return InflationResult(
+                    type = TYPE_DELETE,
+                    reason =
+                        "Removing restored widget: id=${item.appWidgetId} belongs to component ${item.providerName} user ${item.user}, as the provider is null and $removalReason",
+                    restoreErrorType = logReason
+                )
+            }
+
+            // If we do not have a valid id, try to bind an id.
+            if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+                if (!item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
+                    // Id has not been allocated yet. Allocate a new id.
+                    LauncherWidgetHolder.newInstance(context).let {
+                        item.appWidgetId = it.allocateAppWidgetId()
+                        it.destroy()
+                    }
+                    item.restoreStatus =
+                        item.restoreStatus or LauncherAppWidgetInfo.FLAG_ID_ALLOCATED
+
+                    // Also try to bind the widget. If the bind fails, the user will be shown
+                    // a click to setup UI, which will ask for the bind permission.
+                    val pendingInfo = PendingAddWidgetInfo(appWidgetInfo, item.sourceContainer)
+                    pendingInfo.spanX = item.spanX
+                    pendingInfo.spanY = item.spanY
+                    pendingInfo.minSpanX = item.minSpanX
+                    pendingInfo.minSpanY = item.minSpanY
+                    var options = pendingInfo.getDefaultSizeOptions(context)
+                    val isDirectConfig =
+                        item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)
+                    if (isDirectConfig && item.bindOptions != null) {
+                        val newOptions = item.bindOptions.extras
+                        if (options != null) {
+                            newOptions!!.putAll(options)
+                        }
+                        options = newOptions
+                    }
+                    val success =
+                        widgetHelper.bindAppWidgetIdIfAllowed(
+                            item.appWidgetId,
+                            appWidgetInfo,
+                            options
+                        )
+
+                    // We tried to bind once. If we were not able to bind, we would need to
+                    // go through the permission dialog, which means we cannot skip the config
+                    // activity.
+                    item.bindOptions = null
+                    item.restoreStatus =
+                        item.restoreStatus and LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG.inv()
+
+                    // Bind succeeded
+                    if (success) {
+                        // If the widget has a configure activity, it is still needs to set it
+                        // up, otherwise the widget is ready to go.
+                        item.restoreStatus =
+                            if ((appWidgetInfo.configure == null) || isDirectConfig)
+                                LauncherAppWidgetInfo.RESTORE_COMPLETED
+                            else LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+                    }
+                    update = true
+                }
+            } else if (
+                (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) &&
+                    (appWidgetInfo.configure == null))
+            ) {
+                // The widget was marked as UI not ready, but there is no configure activity to
+                // update the UI.
+                item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED
+                update = true
+            } else if (
+                (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_UI_NOT_READY) &&
+                    appWidgetInfo.configure != null)
+            ) {
+                if (widgetHelper.isAppWidgetRestored(item.appWidgetId)) {
+                    item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED
+                    update = true
+                }
+            }
+        }
+
+        if (item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+            // Verify that we own the widget
+            if (appWidgetInfo == null) {
+                FileLog.e(Launcher.TAG, "Removing invalid widget: id=" + item.appWidgetId)
+                return InflationResult(TYPE_DELETE, reason = removalReason)
+            }
+            item.minSpanX = appWidgetInfo.minSpanX
+            item.minSpanY = appWidgetInfo.minSpanY
+            return InflationResult(TYPE_REAL, isUpdate = update, widgetInfo = appWidgetInfo)
+        } else {
+            return InflationResult(TYPE_PENDING, isUpdate = update, widgetInfo = appWidgetInfo)
+        }
+    }
+
+    data class InflationResult(
+        val type: Int,
+        val reason: String? = null,
+        @RestoreError val restoreErrorType: String = RestoreError.APP_NOT_INSTALLED,
+        val isUpdate: Boolean = false,
+        val widgetInfo: LauncherAppWidgetProviderInfo? = null
+    )
+
+    companion object {
+        const val TYPE_DELETE = 0
+
+        const val TYPE_PENDING = 1
+
+        const val TYPE_REAL = 2
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index 0860e72..d293d15 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.widget;
 
+import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
+
 import android.annotation.TargetApi;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -24,10 +26,13 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.widget.RemoteViews;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
-import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.PackageUserKey;
@@ -43,6 +48,7 @@
  */
 public class WidgetManagerHelper {
 
+    private static final String TAG = "WidgetManagerHelper";
     //TODO: replace this with OPTION_APPWIDGET_RESTORE_COMPLETED b/63667276
     public static final String WIDGET_OPTION_RESTORE_COMPLETED = "appWidgetRestoreCompleted";
 
@@ -57,17 +63,24 @@
     /**
      * @see AppWidgetManager#getAppWidgetInfo(int)
      */
+    @Nullable
     public LauncherAppWidgetProviderInfo getLauncherAppWidgetInfo(
             int appWidgetId, ComponentName componentName) {
 
         // For custom widgets.
-        if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID && !CustomWidgetManager
-                .INSTANCE.get(mContext).getWidgetIdForCustomProvider(componentName).equals("")) {
+        if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
             return CustomWidgetManager.INSTANCE.get(mContext).getWidgetProvider(componentName);
         }
 
         AppWidgetProviderInfo info = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
-        return info == null ? null : LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
+        if (info == null) {
+            FileLog.w(TAG,
+                    "getLauncherAppWidgetInfo: AppWidgetManager returned null AppWidgetInfo for"
+                            + " appWidgetId=" + appWidgetId
+                            + ", componentName=" + componentName);
+            return null;
+        }
+        return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
     }
 
     /**
@@ -75,7 +88,7 @@
      */
     @TargetApi(Build.VERSION_CODES.O)
     public List<AppWidgetProviderInfo> getAllProviders(@Nullable PackageUserKey packageUser) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return Collections.emptyList();
         }
 
@@ -100,7 +113,7 @@
      */
     public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info,
             Bundle options) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return false;
         }
         if (appWidgetId <= LauncherAppWidgetInfo.CUSTOM_WIDGET_ID) {
@@ -111,7 +124,7 @@
     }
 
     public LauncherAppWidgetProviderInfo findProvider(ComponentName provider, UserHandle user) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+        if (!WIDGETS_ENABLED) {
             return null;
         }
         for (AppWidgetProviderInfo info :
@@ -127,8 +140,24 @@
      * Returns if a AppWidgetProvider has marked a widget restored
      */
     public boolean isAppWidgetRestored(int appWidgetId) {
-        return !WidgetsModel.GO_DISABLE_WIDGETS && mAppWidgetManager.getAppWidgetOptions(
-                appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
+        return WIDGETS_ENABLED && mAppWidgetManager.getAppWidgetOptions(appWidgetId)
+                .getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
+    }
+
+
+    /**
+     * Load RemoteViews preview for this provider if available.
+     *
+     * @param info           The provider info for the widget you want to preview.
+     * @param widgetCategory The widget category for which you want to display previews.
+     * @return Returns the widget preview that matches selected category, if available.
+     */
+    @Nullable
+    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public RemoteViews loadGeneratedPreview(@NonNull AppWidgetProviderInfo info,
+            int widgetCategory) {
+        if (!android.appwidget.flags.Flags.generatedPreviews()) return null;
+        return mAppWidgetManager.getWidgetPreview(info.provider, info.getProfile(), widgetCategory);
     }
 
     private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index c347939..b14ec42 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -28,6 +28,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.animation.Interpolator;
 import android.widget.ScrollView;
 import android.widget.TableLayout;
@@ -118,6 +119,9 @@
         mContent = findViewById(R.id.widgets_bottom_sheet);
         setContentBackgroundWithParent(
                 getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet), mContent);
+        View scrollView = findViewById(R.id.widgets_table_scroll_view);
+        scrollView.setOutlineProvider(mViewOutlineProvider);
+        scrollView.setClipToOutline(true);
     }
 
     @Override
@@ -212,6 +216,7 @@
     protected WidgetCell addItemCell(ViewGroup parent) {
         WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
                 .inflate(R.layout.widget_cell, parent, false);
+        widget.setOnClickListener(this);
 
         View previewContainer = widget.findViewById(R.id.widget_preview_container);
         previewContainer.setOnClickListener(this);
@@ -277,6 +282,18 @@
     @Override
     public void addHintCloseAnim(
             float distanceToMove, Interpolator interpolator, PendingAnimation target) {
-        target.setInt(this, PADDING_BOTTOM, (int) (distanceToMove + mInsets.bottom), interpolator);
+        target.addAnimatedFloat(mSwipeToDismissProgress, 0f, 1f, interpolator);
+    }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof ScrollView scrollView) {
+                scrollView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
     }
 }
diff --git a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
index 44571a6..398b1df 100644
--- a/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/custom/CustomAppWidgetProviderInfo.java
@@ -33,13 +33,9 @@
 public class CustomAppWidgetProviderInfo extends LauncherAppWidgetProviderInfo
         implements Parcelable {
 
-    public final String providerId;
-
-    protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf, String providerId) {
+    protected CustomAppWidgetProviderInfo(Parcel parcel, boolean readSelf) {
         super(parcel);
         if (readSelf) {
-            this.providerId = parcel.readString();
-
             provider = new ComponentName(parcel.readString(),
                     CLS_CUSTOM_WIDGET_PREFIX + parcel.readString());
 
@@ -53,8 +49,6 @@
             spanY = parcel.readInt();
             minSpanX = parcel.readInt();
             minSpanY = parcel.readInt();
-        } else {
-            this.providerId = providerId;
         }
     }
 
@@ -77,7 +71,6 @@
     @Override
     public void writeToParcel(Parcel out, int flags) {
         super.writeToParcel(out, flags);
-        out.writeString(providerId);
         out.writeString(provider.getPackageName());
         out.writeString(provider.getClassName());
 
@@ -93,12 +86,12 @@
         out.writeInt(minSpanY);
     }
 
-    public static final Parcelable.Creator<CustomAppWidgetProviderInfo> CREATOR
-            = new Parcelable.Creator<CustomAppWidgetProviderInfo>() {
+    public static final Parcelable.Creator<CustomAppWidgetProviderInfo> CREATOR =
+            new Parcelable.Creator<>() {
 
         @Override
         public CustomAppWidgetProviderInfo createFromParcel(Parcel parcel) {
-            return new CustomAppWidgetProviderInfo(parcel, true, "");
+            return new CustomAppWidgetProviderInfo(parcel, true);
         }
 
         @Override
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 7cf0221..05fe8e3 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
 import static com.android.launcher3.model.data.LauncherAppWidgetInfo.CUSTOM_WIDGET_ID;
+import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
 
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
@@ -31,9 +32,9 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.PluginManagerWrapper;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -44,7 +45,6 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 
@@ -57,17 +57,16 @@
             new MainThreadInitializedObject<>(CustomWidgetManager::new);
 
     private static final String TAG = "CustomWidgetManager";
+    private static final String PLUGIN_PKG = "android";
     private final Context mContext;
-    private final HashMap<String, CustomWidgetPlugin> mPlugins;
+    private final HashMap<ComponentName, CustomWidgetPlugin> mPlugins;
     private final List<CustomAppWidgetProviderInfo> mCustomWidgets;
-    private final HashMap<ComponentName, String> mWidgetsIdMap;
     private Consumer<PackageUserKey> mWidgetRefreshCallback;
 
     private CustomWidgetManager(Context context) {
         mContext = context;
         mPlugins = new HashMap<>();
         mCustomWidgets = new ArrayList<>();
-        mWidgetsIdMap = new HashMap<>();
         PluginManagerWrapper.INSTANCE.get(context)
                 .addPluginListener(this, CustomWidgetPlugin.class, true);
 
@@ -78,8 +77,7 @@
                     Class<?> cls = Class.forName(s);
                     CustomWidgetPlugin plugin = (CustomWidgetPlugin)
                             cls.getDeclaredConstructor(Context.class).newInstance(context);
-                    mPlugins.put(plugin.getId(), plugin);
-                    onPluginConnected(mPlugins.get(plugin.getId()), context);
+                    onPluginConnected(plugin, context);
                 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                          | ClassCastException | NoSuchMethodException
                          | InvocationTargetException e) {
@@ -102,35 +100,17 @@
         Parcel parcel = Parcel.obtain();
         providers.get(0).writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
-        CustomAppWidgetProviderInfo info = newInfo(plugin.getId(), plugin, parcel, context);
+        CustomAppWidgetProviderInfo info = newInfo(plugin, parcel);
         parcel.recycle();
+        mPlugins.put(info.provider, plugin);
         mCustomWidgets.add(info);
-        mWidgetsIdMap.put(info.provider, plugin.getId());
     }
 
     @Override
     public void onPluginDisconnected(CustomWidgetPlugin plugin) {
-        String providerId = plugin.getId();
-        if (mPlugins.containsKey(providerId)) {
-            mPlugins.remove(providerId);
-        }
-
-        ComponentName cn = null;
-        for (Map.Entry entry: mWidgetsIdMap.entrySet()) {
-            if (entry.getValue().equals(providerId)) {
-                cn = (ComponentName) entry.getKey();
-            }
-        }
-
-        if (cn != null) {
-            mWidgetsIdMap.remove(cn);
-            for (int i = 0; i < mCustomWidgets.size(); i++) {
-                if (mCustomWidgets.get(i).getComponent().equals(cn)) {
-                    mCustomWidgets.remove(i);
-                    return;
-                }
-            }
-        }
+        ComponentName cn = getWidgetProviderComponent(plugin);
+        mPlugins.remove(cn);
+        mCustomWidgets.removeIf(w -> w.getComponent().equals(cn));
     }
 
     /**
@@ -145,7 +125,7 @@
      */
     public void onViewCreated(LauncherAppWidgetHostView view) {
         CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo();
-        CustomWidgetPlugin plugin = mPlugins.get(info.providerId);
+        CustomWidgetPlugin plugin = mPlugins.get(info.provider);
         if (plugin == null) return;
         plugin.onViewCreated(view);
     }
@@ -159,32 +139,18 @@
     }
 
     /**
-     * Returns the widget id for a specific provider.
-     */
-    public String getWidgetIdForCustomProvider(@NonNull ComponentName provider) {
-        if (mWidgetsIdMap.containsKey(provider)) {
-            return mWidgetsIdMap.get(provider);
-        } else {
-            return "";
-        }
-    }
-
-    /**
      * Returns the widget provider in respect to given widget id.
      */
     @Nullable
-    public LauncherAppWidgetProviderInfo getWidgetProvider(ComponentName componentName) {
-        for (LauncherAppWidgetProviderInfo info : mCustomWidgets) {
-            if (info.provider.equals(componentName)) return info;
-        }
-        return null;
+    public LauncherAppWidgetProviderInfo getWidgetProvider(ComponentName cn) {
+        return mCustomWidgets.stream()
+                .filter(w -> w.getComponent().equals(cn)).findAny().orElse(null);
     }
 
-    private static CustomAppWidgetProviderInfo newInfo(String providerId, CustomWidgetPlugin plugin,
-            Parcel parcel, Context context) {
-        CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(
-                parcel, false, providerId);
-        plugin.updateWidgetInfo(info, context);
+    private CustomAppWidgetProviderInfo newInfo(CustomWidgetPlugin plugin, Parcel parcel) {
+        CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false);
+        info.provider = getWidgetProviderComponent(plugin);
+        plugin.updateWidgetInfo(info, mContext);
         return info;
     }
 
@@ -195,4 +161,8 @@
         return CUSTOM_WIDGET_ID - mCustomWidgets.indexOf(getWidgetProvider(componentName));
     }
 
+    private ComponentName getWidgetProviderComponent(CustomWidgetPlugin plugin) {
+        return new ComponentName(
+                PLUGIN_PKG, CLS_CUSTOM_WIDGET_PREFIX + plugin.getClass().getName());
+    }
 }
diff --git a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
index 68f18ae..0d775c3 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
@@ -36,41 +36,49 @@
             (context, entry) -> entry.mWidgets.stream()
                     .map(item -> item.label).sorted().collect(Collectors.joining(", "));
 
-    private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
-            (context, entry) -> {
-                List<WidgetItem> items = entry.mWidgets;
-                int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
-                int sc = Math.max(0, items.size() - wc);
+    @Nullable
+    private static String buildWidgetsCountString(Context context, int wc, int sc) {
+        Resources resources = context.getResources();
+        if (wc == 0 && sc == 0) {
+            return null;
+        }
 
-                Resources resources = context.getResources();
-                if (wc == 0 && sc == 0) {
-                    return null;
-                }
-
-                String subtitle;
-                if (wc > 0 && sc > 0) {
-                    String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
-                            R.string.widgets_count, wc);
-                    String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
-                            R.string.shortcuts_count, sc);
-                    subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
-                            widgetsCount, shortcutsCount);
-                } else if (wc > 0) {
-                    subtitle = PluralMessageFormat.getIcuPluralString(context,
-                            R.string.widgets_count, wc);
-                } else {
-                    subtitle = PluralMessageFormat.getIcuPluralString(context,
-                            R.string.shortcuts_count, sc);
-                }
-                return subtitle;
-            };
+        String subtitle;
+        if (wc > 0 && sc > 0) {
+            String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
+                    R.string.widgets_count, wc);
+            String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
+                    R.string.shortcuts_count, sc);
+            subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
+                    widgetsCount, shortcutsCount);
+        } else if (wc > 0) {
+            subtitle = PluralMessageFormat.getIcuPluralString(context,
+                    R.string.widgets_count, wc);
+        } else {
+            subtitle = PluralMessageFormat.getIcuPluralString(context,
+                    R.string.shortcuts_count, sc);
+        }
+        return subtitle;
+    }
 
     private final boolean mIsWidgetListShown;
+    /** Selected widgets displayed */
+    private final int mVisibleWidgetsCount;
     private final boolean mIsSearchEntry;
 
     private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
+            List<WidgetItem> items, int visibleWidgetsCount,
+            boolean isSearchEntry, boolean isWidgetListShown) {
+        super(pkgItem, titleSectionName, items);
+        mVisibleWidgetsCount = visibleWidgetsCount;
+        mIsSearchEntry = isSearchEntry;
+        mIsWidgetListShown = isWidgetListShown;
+    }
+
+    private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
             List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
         super(pkgItem, titleSectionName, items);
+        mVisibleWidgetsCount = (int) items.stream().filter(w -> w.widgetInfo != null).count();
         mIsSearchEntry = isSearchEntry;
         mIsWidgetListShown = isWidgetListShown;
     }
@@ -91,8 +99,13 @@
 
     @Nullable
     public String getSubtitle(Context context) {
-        return mIsSearchEntry
-                ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
+        if (mIsSearchEntry) {
+            return SUBTITLE_SEARCH.apply(context, this);
+        } else {
+            int shortcutsCount = Math.max(0,
+                    (int) mWidgets.stream().filter(WidgetItem::isShortcut).count());
+            return buildWidgetsCountString(context, mVisibleWidgetsCount, shortcutsCount);
+        }
     }
 
     @Override
@@ -102,6 +115,7 @@
         return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
                 && mTitleSectionName.equals(otherEntry.mTitleSectionName)
                 && mIsWidgetListShown == otherEntry.mIsWidgetListShown
+                && mVisibleWidgetsCount == otherEntry.mVisibleWidgetsCount
                 && mIsSearchEntry == otherEntry.mIsSearchEntry;
     }
 
@@ -112,6 +126,7 @@
                 mPkgItem,
                 mTitleSectionName,
                 mWidgets,
+                mVisibleWidgetsCount,
                 mIsSearchEntry,
                 /* isWidgetListShown= */ true);
     }
@@ -122,7 +137,28 @@
                 pkgItem,
                 titleSectionName,
                 items,
-                /* forSearch */ false,
+                /* isSearchEntry= */ false,
+                /* isWidgetListShown= */ false);
+    }
+
+    /**
+     * Creates a widget list holder for an header ("app" / "suggestions") which has widgets or/and
+     * shortcuts.
+     *
+     * @param pkgItem             package item info for the header section
+     * @param titleSectionName    title string for the header
+     * @param items               all items for the given header
+     * @param visibleWidgetsCount widgets count when only selected widgets are shown due to
+     *                            limited space.
+     */
+    public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
+            List<WidgetItem> items, int visibleWidgetsCount) {
+        return new WidgetsListHeaderEntry(
+                pkgItem,
+                titleSectionName,
+                items,
+                visibleWidgetsCount,
+                /* isSearchEntry= */ false,
                 /* isWidgetListShown= */ false);
     }
 
@@ -132,7 +168,7 @@
                 pkgItem,
                 titleSectionName,
                 items,
-                /* forSearch */ true,
+                /* isSearchEntry */ true,
                 /* isWidgetListShown= */ false);
     }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java
new file mode 100644
index 0000000..072d1d5
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
+import java.util.Objects;
+
+/**
+ * A category of widget recommendations displayed in the widget picker (launched from "Widgets"
+ * option in the pop-up opened on long press of launcher workspace).
+ */
+public class WidgetRecommendationCategory implements Comparable<WidgetRecommendationCategory> {
+    /** Resource id that holds the user friendly label for the category. */
+    @StringRes
+    public final int categoryTitleRes;
+    /**
+     * Relative order of this category with respect to other categories.
+     *
+     * <p>Category with lowest order is displayed first in the recommendations section.</p>
+     */
+    public final int order;
+
+    public WidgetRecommendationCategory(@StringRes int categoryTitleRes, int order) {
+        this.categoryTitleRes = categoryTitleRes;
+        this.order = order;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(categoryTitleRes, order);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object obj) {
+        if (!(obj instanceof WidgetRecommendationCategory category)) {
+            return false;
+        }
+        return categoryTitleRes == category.categoryTitleRes
+                && order == category.order;
+    }
+
+    @Override
+    public int compareTo(WidgetRecommendationCategory widgetRecommendationCategory) {
+        return order - widgetRecommendationCategory.order;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
new file mode 100644
index 0000000..80bda22
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.WorkerThread;
+
+import com.android.launcher3.R;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.ResourceBasedOverride;
+
+/**
+ * A {@link ResourceBasedOverride} that categorizes widget recommendations.
+ *
+ * <p>Override the {@code widget_recommendation_category_provider_class} resource to provide your
+ * own implementation. Method {@code getWidgetRecommendationCategory} is called per widget to get
+ * the category.</p>
+ */
+public class WidgetRecommendationCategoryProvider implements ResourceBasedOverride {
+    private static final String TAG = "WidgetRecommendationCategoryProvider";
+
+    /**
+     * Retrieve instance of this object that can be overridden in runtime based on the build
+     * variant of the application.
+     */
+    public static WidgetRecommendationCategoryProvider newInstance(Context context) {
+        Preconditions.assertWorkerThread();
+        return Overrides.getObject(
+                WidgetRecommendationCategoryProvider.class, context.getApplicationContext(),
+                R.string.widget_recommendation_category_provider_class);
+    }
+
+    /**
+     * Returns a {@link WidgetRecommendationCategory} for the provided widget item that can be used
+     * to display the recommendation grouped by categories.
+     */
+    @WorkerThread
+    @Nullable
+    public WidgetRecommendationCategory getWidgetRecommendationCategory(Context context,
+            WidgetItem item) {
+        // This is a default implementation that uses application category to derive the category to
+        // be displayed. The implementation can be overridden in individual launcher customization
+        // via the overridden WidgetRecommendationCategoryProvider resource.
+
+        Preconditions.assertWorkerThread();
+        try (PackageManagerHelper pmHelper = new PackageManagerHelper(context)) {
+            if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
+                String widgetComponentName = item.widgetInfo.getComponent().getClassName();
+                ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
+                        item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
+                        0 /* flags */);
+                if (applicationInfo != null) {
+                    int predictionCategory = applicationInfo.category;
+                    return getCategoryFromApplicationCategory(context, predictionCategory,
+                            widgetComponentName);
+                }
+            }
+        }
+        return null;
+    }
+
+    /** Maps application category to an appropriate displayable category. */
+    private static WidgetRecommendationCategory getCategoryFromApplicationCategory(
+            Context context, int applicationCategory, String componentName) {
+        // Weather categories don't map to a specific application category, so, we maintain an
+        // allowlist.
+        String[] weatherRecommendationAllowlist =
+                context.getResources().getStringArray(R.array.weather_recommendations);
+        for (String allowedWeatherComponentName : weatherRecommendationAllowlist) {
+            if (componentName.equalsIgnoreCase(allowedWeatherComponentName)) {
+                return new WidgetRecommendationCategory(
+                        R.string.weather_widget_recommendation_category_label, /*order=*/3);
+            }
+        }
+
+        // Fitness categories don't map to a specific application category, so, we maintain an
+        // allowlist.
+        String[] fitnessRecommendationAllowlist =
+                context.getResources().getStringArray(R.array.fitness_recommendations);
+        for (String allowedFitnessComponentName : fitnessRecommendationAllowlist) {
+            if (componentName.equalsIgnoreCase(allowedFitnessComponentName)) {
+                return new WidgetRecommendationCategory(
+                        R.string.fitness_widget_recommendation_category_label, /*order=*/2);
+            }
+        }
+
+        if (applicationCategory == ApplicationInfo.CATEGORY_PRODUCTIVITY) {
+            return new WidgetRecommendationCategory(
+                    R.string.productivity_widget_recommendation_category_label, /*order=*/0);
+        }
+
+        if (applicationCategory == ApplicationInfo.CATEGORY_NEWS) {
+            return new WidgetRecommendationCategory(
+                    R.string.news_widget_recommendation_category_label, /*order=*/1);
+        }
+
+        if (applicationCategory == ApplicationInfo.CATEGORY_SOCIAL) {
+            return new WidgetRecommendationCategory(
+                    R.string.social_widget_recommendation_category_label,
+                    /*order=*/5);
+        }
+
+        if (applicationCategory == ApplicationInfo.CATEGORY_AUDIO
+                || applicationCategory == ApplicationInfo.CATEGORY_VIDEO
+                || applicationCategory == ApplicationInfo.CATEGORY_IMAGE) {
+            return new WidgetRecommendationCategory(
+                    R.string.entertainment_widget_recommendation_category_label,
+                    /*order=*/6);
+        }
+
+        return new WidgetRecommendationCategory(
+                R.string.others_widget_recommendation_category_label, /*order=*/4);
+    }
+
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
new file mode 100644
index 0000000..4f73e66
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import static com.android.launcher3.widget.util.WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.pageindicators.PageIndicatorDots;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * A {@link PagedView} that displays widget recommendations in categories with dots as paged
+ * indicators.
+ */
+public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots> {
+    private @Px float mAvailableHeight = Float.MAX_VALUE;
+    private static final String INITIALLY_DISPLAYED_WIDGETS_STATE_KEY =
+            "widgetRecommendationsView:mDisplayedWidgets";
+    private static final int MAX_CATEGORIES = 3;
+    private TextView mRecommendationPageTitle;
+    private final List<String> mCategoryTitles = new ArrayList<>();
+
+    /** Callbacks to run when page changes */
+    private final List<Consumer<Integer>> mPageSwitchListeners = new ArrayList<>();
+
+    @Nullable
+    private OnLongClickListener mWidgetCellOnLongClickListener;
+    @Nullable
+    private OnClickListener mWidgetCellOnClickListener;
+    private Set<ComponentName> mDisplayedWidgets = Collections.emptySet();
+
+    public WidgetRecommendationsView(Context context) {
+        this(context, /* attrs= */ null);
+    }
+
+    public WidgetRecommendationsView(Context context, AttributeSet attrs) {
+        this(context, attrs, /* defStyleAttr= */ 0);
+    }
+
+    public WidgetRecommendationsView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public void initParentViews(View parent) {
+        super.initParentViews(parent);
+        mRecommendationPageTitle = parent.findViewById(R.id.recommendations_page_title);
+    }
+
+    /**
+     * Saves the necessary state in the provided bundle. To be called in case of orientation /
+     * other config changes.
+     */
+    public void saveState(Bundle bundle) {
+        // Save the widgets that were displayed, so that, on rotation / fold / unfold, we can
+        // maintain the "initial" set of widgets that user first saw (if they fit).
+        bundle.putParcelableArrayList(INITIALLY_DISPLAYED_WIDGETS_STATE_KEY,
+                new ArrayList<>(mDisplayedWidgets));
+    }
+
+    /**
+     * Restores the state that was saved by the saveState method during orientation / other config
+     * changes.
+     */
+    public void restoreState(Bundle bundle) {
+        ArrayList<ComponentName> componentList;
+        if (Utilities.ATLEAST_T) {
+            componentList = bundle.getParcelableArrayList(
+                    INITIALLY_DISPLAYED_WIDGETS_STATE_KEY, ComponentName.class);
+        } else {
+            componentList = bundle.getParcelableArrayList(
+                    INITIALLY_DISPLAYED_WIDGETS_STATE_KEY);
+        }
+
+        // Restore the "initial" set of widgets that were displayed, so that, on rotation / fold /
+        // unfold, we can maintain the set of widgets that user first saw (if they fit).
+        if (componentList != null) {
+            mDisplayedWidgets = new HashSet<>(componentList);
+        }
+    }
+
+    /** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
+    public void setWidgetCellLongClickListener(OnLongClickListener onLongClickListener) {
+        mWidgetCellOnLongClickListener = onLongClickListener;
+    }
+
+    /** Sets a {@link android.view.View.OnClickListener} for all widget cells in this table. */
+    public void setWidgetCellOnClickListener(OnClickListener widgetCellOnClickListener) {
+        mWidgetCellOnClickListener = widgetCellOnClickListener;
+    }
+
+    /**
+     * Add a callback to run when the current displayed page changes.
+     */
+    public void addPageSwitchListener(Consumer<Integer> pageChangeListener) {
+        mPageSwitchListeners.add(pageChangeListener);
+    }
+
+    /**
+     * Displays all the provided recommendations in a single table if they fit.
+     *
+     * @param recommendedWidgets list of widgets to be displayed in recommendation section.
+     * @param deviceProfile      the current {@link DeviceProfile}
+     * @param availableHeight    height in px that can be used to display the recommendations;
+     *                           recommendations that don't fit in this height won't be shown
+     * @param availableWidth     width in px that the recommendations should display in
+     * @param cellPadding        padding in px that should be applied to each widget in the
+     *                           recommendations
+     * @return number of recommendations that could fit in the available space.
+     */
+    public int setRecommendations(
+            List<WidgetItem> recommendedWidgets, DeviceProfile deviceProfile,
+            final @Px float availableHeight, final @Px int availableWidth,
+            final @Px int cellPadding) {
+        this.mAvailableHeight = availableHeight;
+        clear();
+
+        Set<ComponentName> displayedWidgets = maybeDisplayInTable(recommendedWidgets,
+                deviceProfile,
+                availableWidth, cellPadding);
+
+        if (mDisplayedWidgets.isEmpty()) {
+            // Save the widgets shown for the first time user opened the picker; so that, they can
+            // be maintained across orientation changes.
+            mDisplayedWidgets = displayedWidgets;
+        }
+
+        updateTitleAndIndicator(/* requestedPage= */ 0);
+        return displayedWidgets.size();
+    }
+
+    /**
+     * Displays the recommendations grouped by categories as pages.
+     * <p>In case of a single category, no title is displayed for it.</p>
+     *
+     * @param recommendations a map of widget items per recommendation category
+     * @param deviceProfile   the current {@link DeviceProfile}
+     * @param availableHeight height in px that can be used to display the recommendations;
+     *                        recommendations that don't fit in this height won't be shown
+     * @param availableWidth  width in px that the recommendations should display in
+     * @param cellPadding     padding in px that should be applied to each widget in the
+     *                        recommendations
+     * @param requestedPage   page number to display initially.
+     * @return number of recommendations that could fit in the available space.
+     */
+    public int setRecommendations(
+            Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations,
+            DeviceProfile deviceProfile, final @Px float availableHeight,
+            final @Px int availableWidth, final @Px int cellPadding, final int requestedPage) {
+        this.mAvailableHeight = availableHeight;
+        Context context = getContext();
+        // For purpose of recommendations section, we don't want paging dots to be halved in two
+        // pane display, so, we always provide isTwoPanels = "false".
+        mPageIndicator.setPauseScroll(/*pause=*/true, /*isTwoPanels=*/ false);
+        clear();
+
+        int displayedCategories = 0;
+        Set<ComponentName> allDisplayedWidgets = new HashSet<>();
+
+        // Render top MAX_CATEGORIES in separate tables. Each table becomes a page.
+        for (Map.Entry<WidgetRecommendationCategory, List<WidgetItem>> entry :
+                new TreeMap<>(recommendations).entrySet()) {
+            // If none of the recommendations for the category could fit in the mAvailableHeight, we
+            // don't want to add that category; and we look for the next one.
+            Set<ComponentName> displayedWidgetsForCategory = maybeDisplayInTable(entry.getValue(),
+                    deviceProfile,
+                    availableWidth, cellPadding);
+            if (!displayedWidgetsForCategory.isEmpty()) {
+                mCategoryTitles.add(
+                        context.getResources().getString(entry.getKey().categoryTitleRes));
+                displayedCategories++;
+                allDisplayedWidgets.addAll(displayedWidgetsForCategory);
+            }
+
+            if (displayedCategories == MAX_CATEGORIES) {
+                break;
+            }
+        }
+
+        if (mDisplayedWidgets.isEmpty()) {
+            // Save the widgets shown for the first time user opened the picker; so that, they can
+            // be maintained across orientation changes.
+            mDisplayedWidgets = allDisplayedWidgets;
+        }
+
+        updateTitleAndIndicator(requestedPage);
+        // For purpose of recommendations section, we don't want paging dots to be halved in two
+        // pane display, so, we always provide isTwoPanels = "false".
+        mPageIndicator.setPauseScroll(/*pause=*/false, /*isTwoPanels=*/false);
+        return allDisplayedWidgets.size();
+    }
+
+    private void clear() {
+        mCategoryTitles.clear();
+        removeAllViews();
+        setCurrentPage(0);
+        mPageIndicator.setActiveMarker(0);
+    }
+
+    /** Displays the page title and paging indicator if there are multiple pages. */
+    private void updateTitleAndIndicator(int requestedPage) {
+        boolean showPaginatedView = getPageCount() > 1;
+        int titleAndIndicatorVisibility = showPaginatedView ? View.VISIBLE : View.GONE;
+        mRecommendationPageTitle.setVisibility(titleAndIndicatorVisibility);
+        mPageIndicator.setVisibility(titleAndIndicatorVisibility);
+        if (showPaginatedView) {
+            if (requestedPage <= 0 || requestedPage >= getPageCount()) {
+                requestedPage = 0;
+            }
+            setCurrentPage(requestedPage);
+            mPageIndicator.setActiveMarker(requestedPage);
+            mRecommendationPageTitle.setText(mCategoryTitles.get(requestedPage));
+        }
+    }
+
+    @Override
+    protected void notifyPageSwitchListener(int prevPage) {
+        if (getPageCount() > 1) {
+            // Since the title is outside the paging scroll, we update the title on page switch.
+            int nextPage = getNextPage();
+            mRecommendationPageTitle.setText(mCategoryTitles.get(nextPage));
+            mPageSwitchListeners.forEach(listener -> listener.accept(nextPage));
+            super.notifyPageSwitchListener(prevPage);
+        }
+    }
+
+    @Override
+    protected boolean canScroll(float absVScroll, float absHScroll) {
+        // Allow only horizontal scroll.
+        return (absHScroll > absVScroll) && super.canScroll(absVScroll, absHScroll);
+    }
+
+    @Override
+    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+        super.onScrollChanged(l, t, oldl, oldt);
+        mPageIndicator.setScroll(l, mMaxScroll);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        boolean hasMultiplePages = getChildCount() > 0;
+
+        if (hasMultiplePages) {
+            int finalWidth = MeasureSpec.getSize(widthMeasureSpec);
+            int desiredHeight = 0;
+
+            for (int i = 0; i < getChildCount(); i++) {
+                View child = getChildAt(i);
+                measureChild(child, widthMeasureSpec, heightMeasureSpec);
+                // Use height of tallest child as we have limited height.
+                desiredHeight = Math.max(desiredHeight, child.getMeasuredHeight());
+            }
+
+            int finalHeight = resolveSizeAndState(desiredHeight, heightMeasureSpec, 0);
+            setMeasuredDimension(finalWidth, finalHeight);
+        } else {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    /**
+     * Groups the provided recommendations into rows and displays ones that fit in a table.
+     * <p>Returns the set of widgets that could fit.</p>
+     */
+    private Set<ComponentName> maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
+            DeviceProfile deviceProfile,
+            final @Px int availableWidth, final @Px int cellPadding) {
+        List<WidgetItem> filteredRecommendedWidgets = recommendedWidgets;
+        // Show only those widgets that were displayed when user first opened the picker.
+        if (!mDisplayedWidgets.isEmpty()) {
+            filteredRecommendedWidgets = recommendedWidgets.stream().filter(
+                    w -> mDisplayedWidgets.contains(w.componentName)).toList();
+        }
+        Context context = getContext();
+        LayoutInflater inflater = LayoutInflater.from(context);
+
+        // Since we are limited by space, we don't sort recommendations - to show most relevant
+        // (if possible).
+        List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
+                filteredRecommendedWidgets,
+                context,
+                deviceProfile,
+                availableWidth,
+                cellPadding);
+
+        WidgetsRecommendationTableLayout recommendationsTable =
+                (WidgetsRecommendationTableLayout) inflater.inflate(
+                        R.layout.widget_recommendations_table,
+                        /* root=*/ this,
+                        /* attachToRoot=*/ false);
+        recommendationsTable.setWidgetCellOnClickListener(mWidgetCellOnClickListener);
+        recommendationsTable.setWidgetCellLongClickListener(mWidgetCellOnLongClickListener);
+
+        List<ArrayList<WidgetItem>> displayedItems = recommendationsTable.setRecommendedWidgets(
+                rows,
+                deviceProfile, mAvailableHeight);
+
+        if (!displayedItems.isEmpty()) {
+            addView(recommendationsTable);
+        }
+
+        return displayedItems.stream().flatMap(
+                        items -> items.stream().map(w -> w.componentName))
+                .collect(Collectors.toSet());
+    }
+
+    /** Returns location of a widget cell for displaying the "touch and hold" education tip. */
+    public View getViewForEducationTip() {
+        if (getChildCount() > 0) {
+            // first page (a table layout) -> first item (a widget cell).
+            return ((ViewGroup) getChildAt(0)).getChildAt(0);
+        }
+        return null;
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index e9a590b..28eeb10 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -15,20 +15,19 @@
  */
 package com.android.launcher3.widget.picker;
 
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
 import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 
 import android.animation.Animator;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -39,18 +38,18 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.WindowInsets;
 import android.view.WindowInsetsController;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.Button;
+import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.window.BackEvent;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.RecyclerView;
@@ -72,15 +71,17 @@
 import com.android.launcher3.views.StickyHeaderLayout;
 import com.android.launcher3.views.WidgetsEduView;
 import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.picker.search.SearchModeListener;
 import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
-import com.android.launcher3.widget.util.WidgetsTableUtils;
 import com.android.launcher3.workprofile.PersonalWorkPagedView;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.function.Predicate;
 import java.util.stream.IntStream;
 
@@ -97,9 +98,11 @@
 
     // The widget recommendation table can easily take over the entire screen on devices with small
     // resolution or landscape on phone. This ratio defines the max percentage of content area that
-    // the table can display.
-    private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
-
+    // the table can display with respect to bottom sheet's height.
+    private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.45f;
+    private static final String RECOMMENDATIONS_SAVED_STATE_KEY =
+            "widgetsFullSheet:mRecommendationsCurrentPage";
+    private static final String SUPER_SAVED_STATE_KEY = "widgetsFullSheet:superHierarchyState";
     private final UserCache mUserCache;
     private final UserManagerState mUserManagerState = new UserManagerState();
     private final UserHandle mCurrentUser = Process.myUserHandle();
@@ -107,9 +110,15 @@
             entry -> mCurrentUser.equals(entry.mPkgItem.user);
     private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter;
     protected final boolean mHasWorkProfile;
-    protected boolean mHasRecommendedWidgets;
+    // Number of recommendations displayed
+    protected int mRecommendedWidgetsCount;
+    private List<WidgetItem> mRecommendedWidgets = new ArrayList<>();
+    private Map<WidgetRecommendationCategory, List<WidgetItem>> mRecommendedWidgetsMap =
+            new HashMap<>();
+    protected int mRecommendationsCurrentPage = 0;
     protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
-    @Nullable private ArrowTipView mLatestEducationalTip;
+    @Nullable
+    private ArrowTipView mLatestEducationalTip;
     private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
             new OnLayoutChangeListener() {
                 @Override
@@ -155,24 +164,31 @@
                 }
             };
 
-    @Px private final int mTabsHeight;
+    @Px
+    private final int mTabsHeight;
 
-    @Nullable private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
-    @Nullable private WidgetsRecyclerView mCurrentTouchEventRecyclerView;
-    @Nullable PersonalWorkPagedView mViewPager;
+    @Nullable
+    private WidgetsRecyclerView mCurrentWidgetsRecyclerView;
+    @Nullable
+    private WidgetsRecyclerView mCurrentTouchEventRecyclerView;
+    @Nullable
+    PersonalWorkPagedView mViewPager;
     private boolean mIsInSearchMode;
     private boolean mIsNoWidgetsViewNeeded;
-    @Px private int mMaxSpanPerRow;
+    @Px
+    protected int mMaxSpanPerRow;
     protected DeviceProfile mDeviceProfile;
 
     protected TextView mNoWidgetsView;
     protected StickyHeaderLayout mSearchScrollView;
-    protected WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+    protected WidgetRecommendationsView mWidgetRecommendationsView;
+    protected LinearLayout mWidgetRecommendationsContainer;
     protected View mTabBar;
     protected View mSearchBarContainer;
     protected WidgetsSearchBar mSearchBar;
     protected TextView mHeaderTitle;
     protected RecyclerViewFastScroller mFastScroller;
+    protected int mBottomPadding;
 
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -182,7 +198,8 @@
                 .stream()
                 .anyMatch(user -> mUserCache.getUserInfo(user).isWork());
         mWorkWidgetsFilter = entry -> mHasWorkProfile
-                && mUserCache.getUserInfo(entry.mPkgItem.user).isWork();
+                && mUserCache.getUserInfo(entry.mPkgItem.user).isWork()
+                && !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
         mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
         mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
         mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
@@ -219,12 +236,20 @@
 
         setupViews();
 
-        mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
-        mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
-        mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+        mWidgetRecommendationsContainer = mSearchScrollView.findViewById(
+                R.id.widget_recommendations_container);
+        mWidgetRecommendationsView = mSearchScrollView.findViewById(
+                R.id.widget_recommendations_view);
+        // To save the currently displayed page, so that, it can be requested when rebinding
+        // recommendations with different size constraints.
+        mWidgetRecommendationsView.addPageSwitchListener(
+                newPage -> mRecommendationsCurrentPage = newPage);
+        mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer);
+        mWidgetRecommendationsView.setWidgetCellLongClickListener(this);
+        mWidgetRecommendationsView.setWidgetCellOnClickListener(this);
+
         mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
 
-        onRecommendedWidgetsBound();
         onWidgetsBound();
         setUpEducationViewsIfNeeded();
     }
@@ -283,13 +308,6 @@
         attachScrollbarToRecyclerView(currentRecyclerView);
     }
 
-    @Override
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    public void onBackProgressed(@NonNull BackEvent backEvent) {
-        super.onBackProgressed(backEvent);
-        mFastScroller.setVisibility(backEvent.getProgress() > 0 ? View.INVISIBLE : View.VISIBLE);
-    }
-
     private void attachScrollbarToRecyclerView(WidgetsRecyclerView recyclerView) {
         recyclerView.bindFastScrollbar(mFastScroller);
         if (mCurrentWidgetsRecyclerView != recyclerView) {
@@ -352,7 +370,6 @@
         super.onAttachedToWindow();
         LauncherAppState.getInstance(mActivityContext).getModel()
                 .refreshAndBindWidgetsAndShortcuts(null);
-        onRecommendedWidgetsBound();
     }
 
     @Override
@@ -369,15 +386,16 @@
     @Override
     public void setInsets(Rect insets) {
         super.setInsets(insets);
-        int bottomPadding = Math.max(insets.bottom, mNavBarScrimHeight);
-        setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, bottomPadding);
-        setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, bottomPadding);
+        mBottomPadding = Math.max(insets.bottom, mNavBarScrimHeight);
+        setBottomPadding(mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView, mBottomPadding);
+        setBottomPadding(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView, mBottomPadding);
         if (mHasWorkProfile) {
-            setBottomPadding(mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView, bottomPadding);
+            setBottomPadding(mAdapters.get(AdapterHolder.WORK)
+                    .mWidgetsRecyclerView, mBottomPadding);
         }
-        ((MarginLayoutParams) mNoWidgetsView.getLayoutParams()).bottomMargin = bottomPadding;
+        ((MarginLayoutParams) mNoWidgetsView.getLayoutParams()).bottomMargin = mBottomPadding;
 
-        if (bottomPadding > 0) {
+        if (mBottomPadding > 0) {
             setupNavBarColor();
         } else {
             clearNavBarColor();
@@ -386,6 +404,15 @@
         requestLayout();
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        WindowInsets w = super.onApplyWindowInsets(insets);
+        if (mInsets.bottom != mNavBarScrimHeight) {
+            setInsets(mInsets);
+        }
+        return w;
+    }
+
     private void setBottomPadding(RecyclerView recyclerView, int bottomPadding) {
         recyclerView.setPadding(
                 recyclerView.getPaddingLeft(),
@@ -510,17 +537,27 @@
     }
 
     @Override
-    public void enterSearchMode() {
+    public void enterSearchMode(boolean shouldLog) {
         if (mIsInSearchMode) return;
         setViewVisibilityBasedOnSearch(/*isInSearchMode= */ true);
         attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView);
-        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+        if (shouldLog) {
+            mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+        }
     }
 
     @Override
     public void exitSearchMode() {
         if (!mIsInSearchMode) return;
         onSearchResults(new ArrayList<>());
+        WidgetsRecyclerView searchRecyclerView = mAdapters.get(
+                AdapterHolder.SEARCH).mWidgetsRecyclerView;
+        // Remove all views when exiting the search mode; this prevents animating from stale results
+        // to new ones the next time we enter search mode. By the time recycler view is hidden,
+        // layout may not have happened to clear up existing results. So, instead of waiting for it
+        // to happen, we clear the views here.
+        searchRecyclerView.swapAdapter(
+                searchRecyclerView.getAdapter(), /*removeAndRecycleExistingViews=*/ true);
         setViewVisibilityBasedOnSearch(/*isInSearchMode=*/ false);
         if (mHasWorkProfile) {
             mViewPager.snapToPage(AdapterHolder.PRIMARY);
@@ -537,7 +574,7 @@
     protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
         mIsInSearchMode = isInSearchMode;
         if (isInSearchMode) {
-            mRecommendedWidgetsTable.setVisibility(GONE);
+            mWidgetRecommendationsContainer.setVisibility(GONE);
             if (mHasWorkProfile) {
                 mViewPager.setVisibility(GONE);
                 mTabBar.setVisibility(GONE);
@@ -566,40 +603,48 @@
         if (mIsInSearchMode) {
             return;
         }
-        List<WidgetItem> recommendedWidgets =
-                mActivityContext.getPopupDataProvider().getRecommendedWidgets();
-        mHasRecommendedWidgets = recommendedWidgets.size() > 0;
-        if (mHasRecommendedWidgets) {
-            float noWidgetsViewHeight = 0;
-            if (mIsNoWidgetsViewNeeded) {
-                // Make sure recommended section leaves enough space for noWidgetsView.
-                Rect noWidgetsViewTextBounds = new Rect();
-                mNoWidgetsView.getPaint()
-                        .getTextBounds(mNoWidgetsView.getText().toString(), /* start= */ 0,
-                                mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
-                noWidgetsViewHeight = noWidgetsViewTextBounds.height();
-            }
-            if (!isTwoPane()) {
-                doMeasure(
-                        makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
-                                MeasureSpec.EXACTLY),
-                        makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
-                                MeasureSpec.EXACTLY));
-            }
-            float maxTableHeight = getMaxTableHeight(noWidgetsViewHeight);
 
-            List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
-                    WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(
-                            recommendedWidgets,
-                            mActivityContext,
-                            mActivityContext.getDeviceProfile(),
-                            mMaxSpanPerRow,
-                            mWidgetCellHorizontalPadding);
-            mRecommendedWidgetsTable.setRecommendedWidgets(
-                    recommendedWidgetsInTable, maxTableHeight);
+        if (enableCategorizedWidgetSuggestions()) {
+            // We avoid applying new recommendations when some are already displayed.
+            if (mRecommendedWidgetsMap.isEmpty()) {
+                mRecommendedWidgetsMap =
+                        mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets();
+            }
+            mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
+                    mRecommendedWidgetsMap,
+                    mDeviceProfile,
+                    /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
+                    /* availableWidth= */ mMaxSpanPerRow,
+                    /* cellPadding= */ mWidgetCellHorizontalPadding,
+                    /* requestedPage= */ mRecommendationsCurrentPage
+            );
         } else {
-            mRecommendedWidgetsTable.setVisibility(GONE);
+            if (mRecommendedWidgets.isEmpty()) {
+                mRecommendedWidgets =
+                        mActivityContext.getPopupDataProvider().getRecommendedWidgets();
+            }
+            mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
+                    mRecommendedWidgets,
+                    mDeviceProfile,
+                    /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
+                    /* availableWidth= */ mMaxSpanPerRow,
+                    /* cellPadding= */ mWidgetCellHorizontalPadding
+            );
         }
+        mWidgetRecommendationsContainer.setVisibility(
+                mRecommendedWidgetsCount > 0 ? VISIBLE : GONE);
+    }
+
+    @Px
+    protected float getMaxAvailableHeightForRecommendations() {
+        // There isn't enough space to show recommendations in landscape orientation on phones with
+        // a full sheet design. Tablets use a two pane picker.
+        if (mDeviceProfile.isLandscape) {
+            return 0f;
+        }
+
+        return (mDeviceProfile.heightPx - mDeviceProfile.bottomSheetTopPadding)
+                * RECOMMENDATION_TABLE_HEIGHT_RATIO;
     }
 
     /** b/209579563: "Widgets" header should be focused first. */
@@ -608,13 +653,6 @@
         return mHeaderTitle;
     }
 
-    protected float getMaxTableHeight(float noWidgetsViewHeight) {
-        return (mContent.getMeasuredHeight()
-                - mTabsHeight - getHeaderViewHeight()
-                - noWidgetsViewHeight)
-                * RECOMMENDATION_TABLE_HEIGHT_RATIO;
-    }
-
     private void open(boolean animate) {
         if (animate) {
             if (getPopupContainer().getInsets().bottom > 0) {
@@ -683,9 +721,34 @@
         return sheet;
     }
 
+    @Override
+    public void saveHierarchyState(SparseArray<Parcelable> sparseArray) {
+        Bundle bundle = new Bundle();
+        // With widget picker open, when we open shade to switch theme, Launcher re-creates the
+        // picker and calls save/restore hierarchy state. We save the state of recommendations
+        // across those updates.
+        bundle.putInt(RECOMMENDATIONS_SAVED_STATE_KEY, mRecommendationsCurrentPage);
+        mWidgetRecommendationsView.saveState(bundle);
+        SparseArray<Parcelable> superState = new SparseArray<>();
+        super.saveHierarchyState(superState);
+        bundle.putSparseParcelableArray(SUPER_SAVED_STATE_KEY, superState);
+        sparseArray.put(0, bundle);
+    }
+
+    @Override
+    public void restoreHierarchyState(SparseArray<Parcelable> sparseArray) {
+        Bundle state = (Bundle) sparseArray.get(0);
+        mRecommendationsCurrentPage = state.getInt(
+                RECOMMENDATIONS_SAVED_STATE_KEY, /*defaultValue=*/0);
+        mWidgetRecommendationsView.restoreState(state);
+        super.restoreHierarchyState(state.getSparseParcelableArray(SUPER_SAVED_STATE_KEY));
+    }
+
     private static int getWidgetSheetId(BaseActivity activity) {
         boolean isTwoPane = (activity.getDeviceProfile().isTablet
-                && activity.getDeviceProfile().isLandscape
+                // Enables two pane picker for tablets in all orientations when the
+                // enableCategorizedWidgetSuggestions flag is on.
+                && (activity.getDeviceProfile().isLandscape || enableCategorizedWidgetSuggestions())
                 && !activity.getDeviceProfile().isTwoPanels)
                 // Enables two pane picker for unfolded foldables if the flag is on.
                 || (activity.getDeviceProfile().isTwoPanels && enableUnfoldedTwoPanePicker());
@@ -747,8 +810,7 @@
     @Override
     public void addHintCloseAnim(
             float distanceToMove, Interpolator interpolator, PendingAnimation target) {
-        target.setFloat(getRecyclerView(), VIEW_TRANSLATE_Y, -distanceToMove, interpolator);
-        target.setViewAlpha(getRecyclerView(), 0.5f, interpolator);
+        target.addAnimatedFloat(mSwipeToDismissProgress, 0f, 1f, interpolator);
     }
 
     @Override
@@ -768,8 +830,8 @@
     }
 
     /** private the height, in pixel, + the vertical margins of a given view. */
-    private static int measureHeightWithVerticalMargins(View view) {
-        if (view.getVisibility() != VISIBLE) {
+    protected static int measureHeightWithVerticalMargins(View view) {
+        if (view == null || view.getVisibility() != VISIBLE) {
             return 0;
         }
         MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
@@ -777,38 +839,86 @@
                 + marginLayoutParams.topMargin;
     }
 
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
+    private int getCurrentAdapterHolderType() {
         if (mIsInSearchMode) {
-            mSearchBar.reset();
+            return SEARCH;
+        } else if (mViewPager != null) {
+            return mViewPager.getCurrentPage();
+        } else {
+            return AdapterHolder.PRIMARY;
+        }
+    }
+
+    private void restorePreviousAdapterHolderType(int previousAdapterHolderType) {
+        if (previousAdapterHolderType == AdapterHolder.WORK && mViewPager != null) {
+            mViewPager.setCurrentPage(previousAdapterHolderType);
+        } else if (previousAdapterHolderType == AdapterHolder.SEARCH) {
+            enterSearchMode(false);
         }
     }
 
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
-        if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
-            handleClose(false);
-            show(BaseActivity.fromContext(getContext()), false);
-        } else {
-            reset();
-        }
+        super.onDeviceProfileChanged(dp);
 
-        // When folding/unfolding the foldables, we need to switch between the regular widget picker
-        // and the two pane picker, so we rebuild the picker with the correct layout.
-        if (mDeviceProfile.isTwoPanels != dp.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+        if (shouldRecreateLayout(/*oldDp=*/ mDeviceProfile, /*newDp=*/ dp)) {
+            SparseArray<Parcelable> widgetsState = new SparseArray<>();
+            saveHierarchyState(widgetsState);
             handleClose(false);
-            show(BaseActivity.fromContext(getContext()), false);
+            WidgetsFullSheet sheet = show(BaseActivity.fromContext(getContext()), false);
+            sheet.restoreRecommendations(mRecommendedWidgets, mRecommendedWidgetsMap);
+            sheet.restoreHierarchyState(widgetsState);
+            sheet.restorePreviousAdapterHolderType(getCurrentAdapterHolderType());
+        } else if (!isTwoPane()) {
+            reset();
+            resetExpandedHeaders();
         }
 
         mDeviceProfile = dp;
     }
 
+    private void restoreRecommendations(List<WidgetItem> recommendedWidgets,
+            Map<WidgetRecommendationCategory, List<WidgetItem>> recommendedWidgetsMap) {
+        mRecommendedWidgets = recommendedWidgets;
+        mRecommendedWidgetsMap = recommendedWidgetsMap;
+    }
+
+    /**
+     * Indicates if layout should be re-created on device profile change - so that a different
+     * layout can be displayed.
+     */
+    private static boolean shouldRecreateLayout(DeviceProfile oldDp, DeviceProfile newDp) {
+        // When folding/unfolding the foldables, we need to switch between the regular widget picker
+        // and the two pane picker, so we rebuild the picker with the correct layout.
+        boolean isFoldUnFold =
+                oldDp.isTwoPanels != newDp.isTwoPanels && enableUnfoldedTwoPanePicker();
+        // In tablets, on orientation change we switch between single and two pane picker unless the
+        // categorized suggestions flag was on. With the categorized suggestions feature, we use a
+        // two pane picker across all orientations.
+        boolean useDifferentLayoutOnOrientationChange =
+                (!enableCategorizedWidgetSuggestions() && (newDp.isTablet && !newDp.isTwoPanels
+                        && oldDp.isLandscape != newDp.isLandscape));
+
+        return isFoldUnFold || useDifferentLayoutOnOrientationChange;
+    }
+
+    /**
+     * In widget search mode, we should scale down content inside widget bottom sheet, rather
+     * than the whole bottom sheet, to indicate we will navigate back within the widget
+     * bottom sheet.
+     */
+    @Override
+    public boolean shouldAnimateContentViewInBackSwipe() {
+        return mIsInSearchMode;
+    }
+
     @Override
     public void onBackInvoked() {
         if (mIsInSearchMode) {
             mSearchBar.reset();
-            animateSlideInViewToNoScale();
+            // Posting animation to next frame will let widget sheet finish updating UI first, and
+            // make animation smoother.
+            post(this::animateSwipeToDismissProgressToStart);
         } else {
             super.onBackInvoked();
         }
@@ -823,10 +933,10 @@
         }
     }
 
-    @Nullable private View getViewToShowEducationTip() {
-        if (mRecommendedWidgetsTable.getVisibility() == VISIBLE
-                && mRecommendedWidgetsTable.getChildCount() > 0) {
-            return ((ViewGroup) mRecommendedWidgetsTable.getChildAt(0)).getChildAt(0);
+    @Nullable
+    private View getViewToShowEducationTip() {
+        if (mWidgetRecommendationsContainer.getVisibility() == VISIBLE) {
+            return mWidgetRecommendationsView.getViewForEducationTip();
         }
 
         AdapterHolder adapterHolder = mAdapters.get(mIsInSearchMode
@@ -896,6 +1006,60 @@
         mAdapters.get(AdapterHolder.PRIMARY).mWidgetsRecyclerView.scrollToTop();
     }
 
+    @Override
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        StickyHeaderLayout header = findViewById(R.id.search_and_recommendations_container);
+        if (header == null) {
+            return 0;
+        }
+        Rect cellRect = new Rect();
+        boolean cellIsPartiallyVisible = cell.getGlobalVisibleRect(cellRect);
+        if (cellIsPartiallyVisible) {
+            Rect occludingRect = new Rect();
+            for (View headerChild : header.getStickyChildren()) {
+                Rect childRect = new Rect();
+                boolean childVisible = headerChild.getGlobalVisibleRect(childRect);
+                if (childVisible && childRect.intersect(cellRect)) {
+                    occludingRect.union(childRect);
+                }
+            }
+            if (!occludingRect.isEmpty() && cellRect.top < occludingRect.bottom) {
+                return occludingRect.bottom - cellRect.top;
+            }
+        }
+        return 0;
+    }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof WidgetsRecyclerView recyclerView) {
+                // Scrollable container for main widget list.
+                recyclerView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent instanceof StickyHeaderLayout header) {
+                // Scrollable container for recommendations. We still scroll on the recycler (even
+                // though the recommendations are not in the recycler view) because the
+                // StickyHeaderLayout scroll is connected to the currently visible recycler view.
+                WidgetsRecyclerView recyclerView = findVisibleRecyclerView();
+                if (recyclerView != null) {
+                    recyclerView.smoothScrollBy(0, scrollByY);
+                }
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
+    }
+
+    @Nullable
+    private WidgetsRecyclerView findVisibleRecyclerView() {
+        if (mViewPager != null) {
+            return (WidgetsRecyclerView) mViewPager.getPageAt(mViewPager.getCurrentPage());
+        }
+        return findViewById(R.id.primary_widgets_list_view);
+    }
+
     /** A holder class for holding adapters & their corresponding recycler view. */
     final class AdapterHolder {
         static final int PRIMARY = 0;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index b5e7401..d373a3b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -35,9 +35,9 @@
 import com.android.launcher3.R;
 import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
 import com.android.launcher3.icons.PlaceHolderIconDrawable;
-import com.android.launcher3.icons.cache.HandlerRunnable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.CancellableTask;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
 
@@ -52,8 +52,12 @@
     private static final int[] EXPANDED_DRAWABLE_STATE = new int[] {android.R.attr.state_expanded};
 
     private final int mIconSize;
-
-    @Nullable private HandlerRunnable mIconLoadRequest;
+    /**
+     * Indicates if the header is collapsable. For example, when displayed in a two pane layout,
+     * widget apps aren't collapsable.
+    */
+    private final boolean mIsCollapsable;
+    @Nullable private CancellableTask mIconLoadRequest;
     @Nullable private Drawable mIconDrawable;
     @Nullable private WidgetsListDrawableState mListDrawableState;
     private ImageView mAppIcon;
@@ -79,6 +83,7 @@
                 R.styleable.WidgetsListRowHeader, defStyleAttr, /* defStyleRes= */ 0);
         mIconSize = a.getDimensionPixelSize(R.styleable.WidgetsListRowHeader_appIconSize,
                 grid.iconSizePx);
+        mIsCollapsable = a.getBoolean(R.styleable.WidgetsListRowHeader_collapsable, true);
     }
 
     @Override
@@ -87,32 +92,36 @@
         mAppIcon = findViewById(R.id.app_icon);
         mTitle = findViewById(R.id.app_title);
         mSubtitle = findViewById(R.id.app_subtitle);
-        setAccessibilityDelegate(new AccessibilityDelegate() {
+        // Lists that cannot collapse, don't need EXPAND or COLLAPSE accessibility actions.
+        if (mIsCollapsable) {
+            setAccessibilityDelegate(new AccessibilityDelegate() {
 
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                if (mIsExpanded) {
-                    info.removeAction(AccessibilityNodeInfo.ACTION_EXPAND);
-                    info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
-                } else {
-                    info.removeAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
-                    info.addAction(AccessibilityNodeInfo.ACTION_EXPAND);
+                @Override
+                public void onInitializeAccessibilityNodeInfo(View host,
+                        AccessibilityNodeInfo info) {
+                    if (mIsExpanded) {
+                        info.removeAction(AccessibilityNodeInfo.ACTION_EXPAND);
+                        info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
+                    } else {
+                        info.removeAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
+                        info.addAction(AccessibilityNodeInfo.ACTION_EXPAND);
+                    }
+                    super.onInitializeAccessibilityNodeInfo(host, info);
                 }
-                super.onInitializeAccessibilityNodeInfo(host, info);
-            }
 
-            @Override
-            public boolean performAccessibilityAction(View host, int action, Bundle args) {
-                switch (action) {
-                    case AccessibilityNodeInfo.ACTION_EXPAND:
-                    case AccessibilityNodeInfo.ACTION_COLLAPSE:
-                        callOnClick();
-                        return true;
-                    default:
-                        return super.performAccessibilityAction(host, action, args);
+                @Override
+                public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                    switch (action) {
+                        case AccessibilityNodeInfo.ACTION_EXPAND:
+                        case AccessibilityNodeInfo.ACTION_COLLAPSE:
+                            callOnClick();
+                            return true;
+                        default:
+                            return super.performAccessibilityAction(host, action, args);
+                    }
                 }
-            }
-        });
+            });
+        }
     }
 
     /** Sets the expand toggle to expand / collapse. */
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index c7d2aa3..56352cc 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -119,9 +119,10 @@
                 widget.setVisibility(View.VISIBLE);
 
                 // When preview loads, notify adapter to rebind the item and possibly animate
-                widget.applyFromCellItem(widgetItem, 1f,
+                widget.applyFromCellItem(widgetItem,
                         bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
                         holder.previewCache.get(widgetItem));
+                widget.requestLayout();
             }
         }
     }
@@ -159,6 +160,7 @@
                     WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
                             R.layout.widget_cell, tableRow, false);
                     // set up touch.
+                    widget.setOnClickListener(mIconClickListener);
                     View preview = widget.findViewById(R.id.widget_preview_container);
                     preview.setOnClickListener(mIconClickListener);
                     preview.setOnLongClickListener(mIconLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 06cc65e..03af0cb 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -15,12 +15,15 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
+import static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx;
+import static com.android.launcher3.widget.util.WidgetsTableUtils.WIDGETS_TABLE_ROW_SIZE_COMPARATOR;
+
+import static java.lang.Math.max;
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Size;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -29,27 +32,23 @@
 import android.widget.TableRow;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.Px;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.util.WidgetSizes;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** A {@link TableLayout} for showing recommended widgets. */
 public final class WidgetsRecommendationTableLayout extends TableLayout {
-    private static final String TAG = "WidgetsRecommendationTableLayout";
-    private static final float DOWN_SCALE_RATIO = 0.9f;
-    private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
     private final float mWidgetsRecommendationTableVerticalPadding;
     private final float mWidgetCellVerticalPadding;
     private final float mWidgetCellTextViewsHeight;
 
-    private float mRecommendationTableMaxHeight = Float.MAX_VALUE;
     @Nullable private OnLongClickListener mWidgetCellOnLongClickListener;
     @Nullable private OnClickListener mWidgetCellOnClickListener;
 
@@ -61,7 +60,7 @@
         super(context, attrs);
         // There are 1 row for title, 1 row for dimension and 2 rows for description.
         mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
-                .getDimensionPixelSize(R.dimen.recommended_widgets_table_vertical_padding);
+                .getDimensionPixelSize(R.dimen.widget_recommendations_table_vertical_padding);
         mWidgetCellVerticalPadding = 2 * getResources()
                 .getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
         mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
@@ -82,34 +81,39 @@
      * desired {@code recommendationTableMaxHeight}.
      *
      * <p>If the content can't fit {@code recommendationTableMaxHeight}, this view will remove a
-     * last row from the {@code recommendedWidgets} until it fits or only one row left. If the only
-     * row still doesn't fit, we scale down the preview image.
+     * last row from the {@code recommendedWidgets} until it fits or only one row left.
+     *
+     * <p>Returns the list of widgets that could fit</p>
      */
-    public void setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
-            float recommendationTableMaxHeight) {
-        mRecommendationTableMaxHeight = recommendationTableMaxHeight;
-        RecommendationTableData data = fitRecommendedWidgetsToTableSpace(/* previewScale= */ 1f,
-                recommendedWidgets);
-        bindData(data);
+    public List<ArrayList<WidgetItem>> setRecommendedWidgets(
+            List<ArrayList<WidgetItem>> recommendedWidgets,
+            DeviceProfile deviceProfile, float recommendationTableMaxHeight) {
+        List<ArrayList<WidgetItem>> rows = selectRowsThatFitInAvailableHeight(recommendedWidgets,
+                recommendationTableMaxHeight, deviceProfile);
+        bindData(rows);
+        return rows;
     }
 
-    private void bindData(RecommendationTableData data) {
-        if (data.mRecommendationTable.size() == 0) {
+    private void bindData(List<ArrayList<WidgetItem>> recommendationTable) {
+        if (recommendationTable.isEmpty()) {
             setVisibility(GONE);
             return;
         }
 
         removeAllViews();
 
-        for (int i = 0; i < data.mRecommendationTable.size(); i++) {
-            List<WidgetItem> widgetItems = data.mRecommendationTable.get(i);
+        for (int i = 0; i < recommendationTable.size(); i++) {
+            List<WidgetItem> widgetItems = recommendationTable.get(i);
             TableRow tableRow = new TableRow(getContext());
             tableRow.setGravity(Gravity.TOP);
-
             for (WidgetItem widgetItem : widgetItems) {
                 WidgetCell widgetCell = addItemCell(tableRow);
-                widgetCell.applyFromCellItem(widgetItem, data.mPreviewScale);
-                widgetCell.showBadge();
+                widgetCell.applyFromCellItem(widgetItem);
+                widgetCell.showAppIconInWidgetTitle(true);
+                if (enableCategorizedWidgetSuggestions()) {
+                    widgetCell.showDescription(false);
+                    widgetCell.showDimensions(false);
+                }
             }
             addView(tableRow);
         }
@@ -119,6 +123,7 @@
     private WidgetCell addItemCell(ViewGroup parent) {
         WidgetCell widget = (WidgetCell) LayoutInflater.from(
                 getContext()).inflate(R.layout.widget_cell, parent, false);
+        widget.setOnClickListener(mWidgetCellOnClickListener);
 
         View previewContainer = widget.findViewById(R.id.widget_preview_container);
         previewContainer.setOnClickListener(mWidgetCellOnClickListener);
@@ -130,56 +135,32 @@
         return widget;
     }
 
-    private RecommendationTableData fitRecommendedWidgetsToTableSpace(
-            float previewScale,
-            List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
-        if (previewScale < MAX_DOWN_SCALE_RATIO) {
-            Log.w(TAG, "Hide recommended widgets. Can't down scale previews to " + previewScale);
-            return new RecommendationTableData(List.of(), previewScale);
-        }
+    private List<ArrayList<WidgetItem>> selectRowsThatFitInAvailableHeight(
+            List<ArrayList<WidgetItem>> recommendedWidgets, @Px float recommendationTableMaxHeight,
+            DeviceProfile deviceProfile) {
+        List<ArrayList<WidgetItem>> filteredRows = new ArrayList<>();
         // A naive estimation of the widgets recommendation table height without inflation.
         float totalHeight = mWidgetsRecommendationTableVerticalPadding;
-        DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
-        for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
-            List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
+
+        for (int i = 0; i < recommendedWidgets.size(); i++) {
+            List<WidgetItem> widgetItems = recommendedWidgets.get(i);
             float rowHeight = 0;
             for (int j = 0; j < widgetItems.size(); j++) {
                 WidgetItem widgetItem = widgetItems.get(j);
-                Size widgetSize = WidgetSizes.getWidgetItemSizePx(getContext(), deviceProfile,
-                        widgetItem);
-                float previewHeight = widgetSize.getHeight() * previewScale;
-                rowHeight = Math.max(rowHeight,
-                        previewHeight + mWidgetCellTextViewsHeight + mWidgetCellVerticalPadding);
+                WidgetPreviewContainerSize previewContainerSize =
+                        WidgetPreviewContainerSize.Companion.forItem(widgetItem, deviceProfile);
+                float widgetItemHeight = getWidgetSizePx(deviceProfile, previewContainerSize.spanX,
+                        previewContainerSize.spanY).getHeight();
+                rowHeight = max(rowHeight,
+                        widgetItemHeight + mWidgetCellTextViewsHeight + mWidgetCellVerticalPadding);
             }
-            totalHeight += rowHeight;
+            if (totalHeight + rowHeight <= recommendationTableMaxHeight) {
+                totalHeight += rowHeight;
+                filteredRows.add(new ArrayList<>(widgetItems));
+            }
         }
 
-        if (totalHeight < mRecommendationTableMaxHeight) {
-            return new RecommendationTableData(recommendedWidgetsInTable, previewScale);
-        }
-
-        if (recommendedWidgetsInTable.size() > 1) {
-            // We don't want to scale down widgets preview unless we really need to. Reduce the
-            // num of row by 1 to see if it fits.
-            return fitRecommendedWidgetsToTableSpace(
-                    previewScale,
-                    recommendedWidgetsInTable.subList(/* fromIndex= */0,
-                            /* toIndex= */recommendedWidgetsInTable.size() - 1));
-        }
-
-        float nextPreviewScale = previewScale * DOWN_SCALE_RATIO;
-        return fitRecommendedWidgetsToTableSpace(nextPreviewScale, recommendedWidgetsInTable);
-    }
-
-    /** Data class for the widgets recommendation table and widgets preview scaling. */
-    private class RecommendationTableData {
-        private final List<ArrayList<WidgetItem>> mRecommendationTable;
-        private final float mPreviewScale;
-
-        RecommendationTableData(List<ArrayList<WidgetItem>> recommendationTable,
-                float previewScale) {
-            mRecommendationTable = recommendationTable;
-            mPreviewScale = previewScale;
-        }
+        // Perform re-ordering once we have filtered out recommendations that fit.
+        return filteredRows.stream().sorted(WIDGETS_TABLE_ROW_SIZE_COMPARATOR).toList();
     }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 698e764..a47818f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -73,7 +73,7 @@
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
     @Override
-    public String scrollToPositionAtProgress(float touchFraction) {
+    public CharSequence scrollToPositionAtProgress(float touchFraction) {
         // Skip early if widgets are not bound.
         if (isModelNotReady()) {
             return "";
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index c3ab08c..2a2feed 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -15,16 +15,21 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
 import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
+import static com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER;
+import static com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER;
+import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
+import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
 
 import android.content.Context;
-import android.graphics.Outline;
+import android.graphics.Rect;
 import android.os.Process;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewOutlineProvider;
+import android.view.ViewParent;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
@@ -32,11 +37,13 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Px;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
@@ -55,28 +62,21 @@
     private static final int MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP = 395;
     private static final String SUGGESTIONS_PACKAGE_NAME = "widgets_list_suggestions_entry";
 
-    private LinearLayout mSuggestedWidgetsContainer;
+    // This ratio defines the max percentage of content area that the recommendations can display
+    // with respect to the bottom sheet's height.
+    private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.75f;
+    private FrameLayout mSuggestedWidgetsContainer;
     private WidgetsListHeader mSuggestedWidgetsHeader;
+    private PackageUserKey mSuggestedWidgetsPackageUserKey;
+    private View mPrimaryWidgetListView;
     private LinearLayout mRightPane;
 
     private ScrollView mRightPaneScrollView;
     private WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
-    private int mActivePage = -1;
 
-    private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
-        @Override
-        public void getOutline(View view, Outline outline) {
-            outline.setRoundRect(
-                    0,
-                    0,
-                    view.getMeasuredWidth(),
-                    view.getMeasuredHeight() - getResources().getDimensionPixelSize(
-                            R.dimen.widget_list_horizontal_margin_two_pane),
-                    view.getResources().getDimensionPixelSize(
-                            R.dimen.widget_list_top_bottom_corner_radius)
-            );
-        }
-    };
+    private boolean mOldIsSwipeToDismissInProgress;
+    private int mActivePage = -1;
+    private PackageUserKey mSelectedHeader;
 
     public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -106,16 +106,28 @@
 
         mWidgetsListTableViewHolderBinder =
                 new WidgetsListTableViewHolderBinder(mActivityContext, layoutInflater, this, this);
-        mRecommendedWidgetsTable = mContent.findViewById(R.id.recommended_widget_table);
-        mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
-        mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+
+        mWidgetRecommendationsContainer = mContent.findViewById(
+                R.id.widget_recommendations_container);
+        mWidgetRecommendationsView = mContent.findViewById(
+                R.id.widget_recommendations_view);
+        mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer);
+        mWidgetRecommendationsView.setWidgetCellLongClickListener(this);
+        mWidgetRecommendationsView.setWidgetCellOnClickListener(this);
+        // To save the currently displayed page, so that, it can be requested when rebinding
+        // recommendations with different size constraints.
+        mWidgetRecommendationsView.addPageSwitchListener(
+                newPage -> mRecommendationsCurrentPage = newPage);
+
         mHeaderTitle = mContent.findViewById(R.id.title);
         mRightPane = mContent.findViewById(R.id.right_pane);
-        mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
         mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
         mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
 
-        onRecommendedWidgetsBound();
+        mPrimaryWidgetListView = findViewById(R.id.primary_widgets_list_view);
+        mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider);
+        mPrimaryWidgetListView.setClipToOutline(true);
+
         onWidgetsBound();
         setUpEducationViewsIfNeeded();
 
@@ -124,6 +136,47 @@
     }
 
     @Override
+    protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
+        if (enableCategorizedWidgetSuggestions()) {
+            // two pane picker is full width for fold as well as tablet.
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_two_panels_left_right_margin);
+        }
+        if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            // enableUnfoldedTwoPanePicker made two pane picker full-width for fold only.
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_two_panels_left_right_margin);
+        }
+        if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+            // non-fold tablet landscape margins (ag/22163531)
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_landscape_tablet_left_right_margin);
+        }
+        return deviceProfile.allAppsLeftRightMargin;
+    }
+
+    @Override
+    protected void onUserSwipeToDismissProgressChanged() {
+        super.onUserSwipeToDismissProgressChanged();
+        boolean isSwipeToDismissInProgress = mSwipeToDismissProgress.value > 0;
+        if (isSwipeToDismissInProgress == mOldIsSwipeToDismissInProgress) {
+            return;
+        }
+        mOldIsSwipeToDismissInProgress = isSwipeToDismissInProgress;
+        if (isSwipeToDismissInProgress) {
+            modifyAttributesOnViewTree(mPrimaryWidgetListView, (ViewParent) mContent,
+                    CLIP_CHILDREN_FALSE_MODIFIER);
+            modifyAttributesOnViewTree(mRightPaneScrollView,  (ViewParent) mContent,
+                    CLIP_CHILDREN_FALSE_MODIFIER, CLIP_TO_PADDING_FALSE_MODIFIER);
+        } else {
+            restoreAttributesOnViewTree(mPrimaryWidgetListView, mContent,
+                    CLIP_CHILDREN_FALSE_MODIFIER);
+            restoreAttributesOnViewTree(mRightPaneScrollView, mContent,
+                    CLIP_CHILDREN_FALSE_MODIFIER, CLIP_TO_PADDING_FALSE_MODIFIER);
+        }
+    }
+
+    @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
         if (changed && mDeviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
@@ -143,6 +196,23 @@
             }
             layoutParams.weight = layoutParams.width == 0 ? 0.33F : 0;
             leftPane.setLayoutParams(layoutParams);
+            requestApplyInsets();
+            if (mSelectedHeader != null) {
+                if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
+                    mSuggestedWidgetsHeader.callOnClick();
+                } else {
+                    getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onWidgetsBound() {
+        super.onWidgetsBound();
+        if (mRecommendedWidgetsCount == 0 && mSelectedHeader == null) {
+            mAdapters.get(mActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
+            mAdapters.get(mActivePage).mWidgetsRecyclerView.scrollToTop();
         }
     }
 
@@ -150,7 +220,7 @@
     public void onRecommendedWidgetsBound() {
         super.onRecommendedWidgetsBound();
 
-        if (mSuggestedWidgetsContainer == null && mHasRecommendedWidgets) {
+        if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
             setupSuggestedWidgets(LayoutInflater.from(getContext()));
             mSuggestedWidgetsHeader.callOnClick();
         }
@@ -175,11 +245,18 @@
                 return false;
             }
         };
-        packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+        String suggestionsHeaderTitle = getContext().getString(
+                R.string.suggested_widgets_header_title);
+        String suggestionsRightPaneTitle = getContext().getString(
+                R.string.widget_picker_right_pane_accessibility_title, suggestionsHeaderTitle);
+        packageItemInfo.title = suggestionsHeaderTitle;
+        // Suggestions may update at run time. The widgets count on suggestions doesn't add any
+        // value, so, we don't show the count.
         WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
                         packageItemInfo,
-                        getContext().getString(R.string.suggested_widgets_header_title),
-                        mActivityContext.getPopupDataProvider().getRecommendedWidgets())
+                        /*titleSectionName=*/ suggestionsHeaderTitle,
+                        /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
+                        /*visibleWidgetsCount=*/ 0)
                 .withWidgetListShown();
 
         mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
@@ -189,15 +266,27 @@
             mSuggestedWidgetsHeader.setExpanded(true);
             resetExpandedHeaders();
             mRightPane.removeAllViews();
-            mRightPane.addView(mRecommendedWidgetsTable);
+            mRightPane.addView(mWidgetRecommendationsContainer);
             mRightPaneScrollView.setScrollY(0);
+            mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
+            mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
+            mSelectedHeader = mSuggestedWidgetsPackageUserKey;
         });
         mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+        mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
     }
 
     @Override
-    protected float getMaxTableHeight(float noWidgetsViewHeight) {
-        return Float.MAX_VALUE;
+    @Px
+    protected float getMaxAvailableHeightForRecommendations() {
+        if (mRecommendedWidgetsCount > 0) {
+            // If widgets were already selected for display, we show them all on orientation change
+            // in a two pane picker
+            return Float.MAX_VALUE;
+        }
+
+        return (mDeviceProfile.heightPx - mDeviceProfile.bottomSheetTopPadding)
+                * RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE;
     }
 
     @Override
@@ -269,6 +358,7 @@
         return new HeaderChangeListener() {
             @Override
             public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
+                mSelectedHeader = selectedHeader;
                 WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
                         .getSelectedAppWidgets(selectedHeader);
 
@@ -279,30 +369,79 @@
                 if (mSuggestedWidgetsHeader != null) {
                     mSuggestedWidgetsHeader.setExpanded(false);
                 }
+
+                WidgetsListContentEntry contentEntryToBind;
+                if (enableCategorizedWidgetSuggestions()) {
+                    // Setting max span size enables row to understand how to fit more than one item
+                    // in a row.
+                    contentEntryToBind = contentEntry.withMaxSpanSize(mMaxSpanPerRow);
+                } else {
+                    contentEntryToBind = contentEntry;
+                }
+
                 WidgetsRowViewHolder widgetsRowViewHolder =
                         mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
                 mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
-                        contentEntry,
+                        contentEntryToBind,
                         ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
                         Collections.EMPTY_LIST);
                 widgetsRowViewHolder.mDataCallback = data -> {
                     mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
-                            contentEntry,
+                            contentEntryToBind,
                             ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
                             Collections.singletonList(data));
                 };
                 mRightPane.removeAllViews();
                 mRightPane.addView(widgetsRowViewHolder.itemView);
                 mRightPaneScrollView.setScrollY(0);
+                mRightPane.setAccessibilityPaneTitle(
+                        getContext().getString(
+                                R.string.widget_picker_right_pane_accessibility_title,
+                                contentEntry.mPkgItem.title));
             }
         };
     }
 
     @Override
+    public void setInsets(Rect insets) {
+        super.setInsets(insets);
+        FrameLayout rightPaneContainer = mContent.findViewById(R.id.right_pane_container);
+        rightPaneContainer.setPadding(
+                rightPaneContainer.getPaddingLeft(),
+                rightPaneContainer.getPaddingTop(),
+                rightPaneContainer.getPaddingRight(),
+                mBottomPadding);
+        requestLayout();
+    }
+
+    @Override
+    protected int getWidgetListHorizontalMargin() {
+        return getResources().getDimensionPixelSize(
+                R.dimen.widget_list_left_pane_horizontal_margin);
+    }
+
+    @Override
     protected boolean isTwoPane() {
         return true;
     }
 
+    @Override
+    protected int getHeaderTopClip(@NonNull WidgetCell cell) {
+        return 0;
+    }
+
+    @Override
+    protected void scrollCellContainerByY(WidgetCell wc, int scrollByY) {
+        for (ViewParent parent = wc.getParent(); parent != null; parent = parent.getParent()) {
+            if (parent instanceof ScrollView scrollView) {
+                scrollView.smoothScrollBy(0, scrollByY);
+                return;
+            } else if (parent == this) {
+                return;
+            }
+        }
+    }
+
     /**
      * This is a listener for when the selected header gets changed in the left pane.
      */
diff --git a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
index cee7d67..b2620d0 100644
--- a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
+++ b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
@@ -26,7 +26,7 @@
     /**
      * Notifies the subscriber when user enters widget picker search mode.
      */
-    void enterSearchMode();
+    void enterSearchMode(boolean shouldLog);
 
     /**
      * Notifies the subscriber when user exits widget picker search mode.
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
index a15508a..2d96cbd 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
@@ -70,7 +70,7 @@
             mCancelButton.setVisibility(GONE);
         } else {
             mSearchAlgorithm.cancel(/* interruptActiveRequests= */ false);
-            mSearchModeListener.enterSearchMode();
+            mSearchModeListener.enterSearchMode(true);
             mSearchAlgorithm.doSearch(mQuery, this);
             mCancelButton.setVisibility(VISIBLE);
         }
diff --git a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt
new file mode 100644
index 0000000..a0414ba
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.model.WidgetItem
+import kotlin.math.abs
+
+/** Size of a preview container in terms of the grid spans. */
+data class WidgetPreviewContainerSize(@JvmField val spanX: Int, @JvmField val spanY: Int) {
+    companion object {
+        /**
+         * Returns the size of the preview container in which the given widget's preview should be
+         * displayed (by scaling it if necessary).
+         */
+        fun forItem(item: WidgetItem, dp: DeviceProfile): WidgetPreviewContainerSize {
+            val sizes =
+                if (dp.isTablet && !dp.isTwoPanels) {
+                    TABLET_WIDGET_PREVIEW_SIZES
+                } else {
+                    HANDHELD_WIDGET_PREVIEW_SIZES
+                }
+
+            for ((index, containerSize) in sizes.withIndex()) {
+                if (containerSize.spanX == item.spanX && containerSize.spanY == item.spanY) {
+                    return containerSize // Exact match!
+                }
+                if (containerSize.spanX <= item.spanX && containerSize.spanY <= item.spanY) {
+                    return findClosestFittingContainer(
+                        containerSizes = sizes.toList(),
+                        startIndex = index,
+                        item = item
+                    )
+                }
+            }
+            // Use largest container if no match found
+            return sizes.elementAt(0)
+        }
+
+        private fun findClosestFittingContainer(
+            containerSizes: List<WidgetPreviewContainerSize>,
+            startIndex: Int,
+            item: WidgetItem
+        ): WidgetPreviewContainerSize {
+            // Checks if it's a smaller container, but close enough to keep the down-scale minimal.
+            fun hasAcceptableSize(currentIndex: Int): Boolean {
+                val container = containerSizes[currentIndex]
+                val isSmallerThanItem =
+                    container.spanX <= item.spanX && container.spanY <= item.spanY
+                val isCloseToItemSize =
+                    (item.spanY - container.spanY <= 1) && (item.spanX - container.spanX <= 1)
+
+                return isSmallerThanItem && isCloseToItemSize
+            }
+
+            var currentIndex = startIndex
+            var match = containerSizes[currentIndex]
+            val itemCellSizeRatio = item.spanX.toFloat() / item.spanY
+            var lastCellSizeRatioDiff = Float.MAX_VALUE
+
+            // Look for a smaller container (up to an acceptable extent) with closest cell size
+            // ratio.
+            while (currentIndex <= containerSizes.lastIndex && hasAcceptableSize(currentIndex)) {
+                val current = containerSizes[currentIndex]
+                val currentCellSizeRatio = current.spanX.toFloat() / current.spanY
+                val currentCellSizeRatioDiff = abs(itemCellSizeRatio - currentCellSizeRatio)
+
+                if (currentCellSizeRatioDiff < lastCellSizeRatioDiff) {
+                    lastCellSizeRatioDiff = currentCellSizeRatioDiff
+                    match = containerSizes[currentIndex]
+                }
+                currentIndex++
+            }
+            return match
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
new file mode 100644
index 0000000..a016676
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+/**
+ * An ordered list of recommended sizes for the preview containers in handheld devices.
+ *
+ * Size of the preview container in which a widget's preview can be displayed.
+ */
+val HANDHELD_WIDGET_PREVIEW_SIZES: List<WidgetPreviewContainerSize> =
+    listOf(
+        WidgetPreviewContainerSize(spanX = 4, spanY = 3),
+        WidgetPreviewContainerSize(spanX = 4, spanY = 2),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 3),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 2),
+        WidgetPreviewContainerSize(spanX = 4, spanY = 1),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 1),
+        WidgetPreviewContainerSize(spanX = 1, spanY = 1),
+    )
+
+/**
+ * An ordered list of recommended sizes for the preview containers in tablet devices (with larger
+ * grids).
+ *
+ * Size of the preview container in which a widget's preview can be displayed (by scaling the
+ * preview if necessary).
+ */
+val TABLET_WIDGET_PREVIEW_SIZES: List<WidgetPreviewContainerSize> =
+    listOf(
+        WidgetPreviewContainerSize(spanX = 3, spanY = 4),
+        WidgetPreviewContainerSize(spanX = 3, spanY = 3),
+        WidgetPreviewContainerSize(spanX = 3, spanY = 2),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 3),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 2),
+        WidgetPreviewContainerSize(spanX = 3, spanY = 1),
+        WidgetPreviewContainerSize(spanX = 2, spanY = 1),
+        WidgetPreviewContainerSize(spanX = 1, spanY = 1),
+    )
diff --git a/src/com/android/launcher3/widget/util/WidgetSizes.java b/src/com/android/launcher3/widget/util/WidgetSizes.java
index 7049509..4688359 100644
--- a/src/com/android/launcher3/widget/util/WidgetSizes.java
+++ b/src/com/android/launcher3/widget/util/WidgetSizes.java
@@ -15,8 +15,11 @@
  */
 package com.android.launcher3.widget.util;
 
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Point;
@@ -91,20 +94,33 @@
      */
     public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Context context,
             int spanX, int spanY) {
-        AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
-        int widgetId = widgetView.getAppWidgetId();
-        if (widgetId <= 0) {
+        updateWidgetSizeRangesAsync(
+                widgetView.getAppWidgetId(), widgetView.getAppWidgetInfo(), context, spanX, spanY);
+    }
+
+    /**
+     * Updates a given {@code widgetId} with size, {@code spanX}, {@code spanY} asynchronously.
+     *
+     * <p>On Android S+, it also updates the given {@code widgetView} with a list of sizes derived
+     * from {@code spanX}, {@code spanY} in all supported device profiles.
+     */
+    public static void updateWidgetSizeRangesAsync(int widgetId,
+            AppWidgetProviderInfo info, Context context, int spanX, int spanY) {
+        if (widgetId <= 0 || info == null) {
             return;
         }
-        Bundle sizeOptions = getWidgetSizeOptions(context, widgetView.getAppWidgetInfo().provider,
-                spanX, spanY);
-        if (sizeOptions.<SizeF>getParcelableArrayList(
-                AppWidgetManager.OPTION_APPWIDGET_SIZES).equals(
-                widgetManager.getAppWidgetOptions(widgetId).<SizeF>getParcelableArrayList(
-                        AppWidgetManager.OPTION_APPWIDGET_SIZES))) {
-            return;
-        }
-        widgetManager.updateAppWidgetOptions(widgetId, sizeOptions);
+
+        UI_HELPER_EXECUTOR.execute(() -> {
+            AppWidgetManager widgetManager = AppWidgetManager.getInstance(context);
+            Bundle sizeOptions = getWidgetSizeOptions(context, info.provider, spanX, spanY);
+            if (sizeOptions.<SizeF>getParcelableArrayList(
+                    AppWidgetManager.OPTION_APPWIDGET_SIZES).equals(
+                    widgetManager.getAppWidgetOptions(widgetId).<SizeF>getParcelableArrayList(
+                            AppWidgetManager.OPTION_APPWIDGET_SIZES))) {
+                return;
+            }
+            widgetManager.updateAppWidgetOptions(widgetId, sizeOptions);
+        });
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index 74d3062..5e0e203 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -16,11 +16,13 @@
 package com.android.launcher3.widget.util;
 
 import android.content.Context;
+import android.util.Size;
 
 import androidx.annotation.Px;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -33,8 +35,8 @@
     /**
      * Groups widgets in the following order:
      * 1. Widgets always go before shortcuts.
-     * 2. Widgets with smaller horizontal spans will be shown first.
-     * 3. If widgets have the same horizontal spans, then widgets with a smaller vertical spans will
+     * 2. Widgets with smaller vertical spans will be shown first.
+     * 3. If widgets have the same vertical spans, then widgets with a smaller horizontal spans will
      *    go first.
      * 4. If both widgets have the same horizontal and vertical spans, they will use the same order
      *    from the given {@code widgetItems}.
@@ -43,14 +45,29 @@
         if (item.widgetInfo != null && otherItem.widgetInfo == null) return -1;
 
         if (item.widgetInfo == null && otherItem.widgetInfo != null) return 1;
-        if (item.spanX == otherItem.spanX) {
-            if (item.spanY == otherItem.spanY) return 0;
-            return item.spanY > otherItem.spanY ? 1 : -1;
+        if (item.spanY == otherItem.spanY) {
+            if (item.spanX == otherItem.spanX) return 0;
+            return item.spanX > otherItem.spanX ? 1 : -1;
         }
-        return item.spanX > otherItem.spanX ? 1 : -1;
+        return item.spanY > otherItem.spanY ? 1 : -1;
     };
 
     /**
+     * Comparator that enables displaying rows in increasing order of their size (totalW * H);
+     * except for shortcuts which always show at the bottom.
+     */
+    public static final Comparator<ArrayList<WidgetItem>> WIDGETS_TABLE_ROW_SIZE_COMPARATOR =
+            Comparator.comparingInt(row -> {
+                if (row.stream().anyMatch(WidgetItem::isShortcut)) {
+                    return Integer.MAX_VALUE;
+                } else {
+                    int rowWidth = row.stream().mapToInt(w -> w.spanX).sum();
+                    int rowHeight = row.get(0).spanY;
+                    return (rowWidth * rowHeight);
+                }
+            });
+
+    /**
      * Groups {@code widgetItems} items into a 2D array which matches their appearance in a UI
      * table. This takes liberty to rearrange widgets to make the table visually appealing.
      */
@@ -59,72 +76,70 @@
             final @Px int rowPx, final @Px int cellPadding) {
         List<WidgetItem> sortedWidgetItems = widgetItems.stream().sorted(WIDGET_SHORTCUT_COMPARATOR)
                 .collect(Collectors.toList());
-        return groupWidgetItemsUsingRowPxWithoutReordering(sortedWidgetItems, context, dp, rowPx,
+        List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
+                sortedWidgetItems, context, dp, rowPx,
                 cellPadding);
+        return rows.stream().sorted(WIDGETS_TABLE_ROW_SIZE_COMPARATOR).toList();
     }
 
     /**
      * Groups {@code widgetItems} into a 2D array which matches their appearance in a UI table while
      * maintaining their order. This function is a variant of
-     * {@code groupWidgetItemsIntoTableWithoutReordering} in that this uses widget pixels for
-     * calculation.
+     * {@code groupWidgetItemsIntoTableWithoutReordering} in that this uses widget container's
+     * pixels for calculation.
      *
      * <p>Grouping:
      * 1. Widgets and shortcuts never group together in the same row.
-     * 2. The ordered widgets are grouped together in the same row until their individual occupying
-     *    pixels exceed the total allowed pixels for the cell.
+     * 2. Widgets are grouped together only if they have same preview container size.
+     * 3. Widgets are grouped together in the same row until the total of individual container sizes
+     *    exceed the total allowed pixels for the row.
      * 3. The ordered shortcuts are grouped together in the same row until their individual
      *    occupying pixels exceed the total allowed pixels for the cell.
      * 4. If there is only one widget in a row, its width may exceed the {@code rowPx}.
      *
-     * <p>Let's say the {@code rowPx} is set to 600 and we have 5 widgets. Widgets can be grouped
-     * in the same row if each of their individual occupying pixels does not exceed
-     * {@code rowPx} / 5 - 2 * {@code cellPadding}.
-     * Example 1: Row 1: 200x200, 200x300, 100x100. Average horizontal pixels is 200 and no widgets
-     * exceed that width. This is okay.
-     * Example 2: Row 1: 200x200, 400x300, 100x100. Average horizontal pixels is 200 and one widget
-     * exceed that width. This is not allowed.
-     * Example 3: Row 1: 700x400. This is okay because this is the only item in the row.
+     * <p>See WidgetTableUtilsTest
      */
     public static List<ArrayList<WidgetItem>> groupWidgetItemsUsingRowPxWithoutReordering(
             List<WidgetItem> widgetItems, Context context, final DeviceProfile dp,
             final @Px int rowPx, final @Px int cellPadding) {
-
         List<ArrayList<WidgetItem>> widgetItemsTable = new ArrayList<>();
         ArrayList<WidgetItem> widgetItemsAtRow = null;
+        // A row displays only items of same container size.
+        WidgetPreviewContainerSize containerSizeForRow = null;
+        @Px int currentRowWidth = 0;
+
         for (WidgetItem widgetItem : widgetItems) {
             if (widgetItemsAtRow == null) {
                 widgetItemsAtRow = new ArrayList<>();
                 widgetItemsTable.add(widgetItemsAtRow);
             }
             int numOfWidgetItems = widgetItemsAtRow.size();
-            @Px int individualSpan = (rowPx / (numOfWidgetItems + 1)) - (2 * cellPadding);
+
+            WidgetPreviewContainerSize containerSize =
+                    WidgetPreviewContainerSize.Companion.forItem(widgetItem, dp);
+            Size containerSizePx = WidgetSizes.getWidgetSizePx(dp, containerSize.spanX,
+                    containerSize.spanY);
+            @Px int containerWidth = containerSizePx.getWidth() + (2 * cellPadding);
+
             if (numOfWidgetItems == 0) {
                 widgetItemsAtRow.add(widgetItem);
-            } else if (
-                    // Since the size of the widget cell is determined by dividing the maximum span
-                    // pixels evenly, making sure that each widget would have enough span pixels to
-                    // show their contents.
-                    widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
-                    && widgetItemsAtRow.stream().allMatch(
-                            item -> WidgetSizes.getWidgetItemSizePx(context, dp, item)
-                                    .getWidth() <= individualSpan)
-                    && WidgetSizes.getWidgetItemSizePx(context, dp, widgetItem)
-                            .getWidth() <= individualSpan) {
+                containerSizeForRow = containerSize;
+                currentRowWidth = containerWidth;
+            } else if ((currentRowWidth + containerWidth) <= rowPx
+                    && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
+                    && containerSize.equals(containerSizeForRow)) {
                 // Group items in the same row if
                 // 1. they are with the same type, i.e. a row can only have widgets or shortcuts but
                 //    never a mix of both.
-                // 2. Each widget will have horizontal cell span pixels that is at least as large as
-                //    it is required to fit in the horizontal content, unless the widget horizontal
-                //    span pixels is larger than the maximum allowed.
-                //    If an item has horizontal span pixels larger than the maximum allowed pixels
-                //    per row, we just place it in its own row regardless of the horizontal span
-                //    limit.
+                // 2. Each widget in the given row has same preview container size.
                 widgetItemsAtRow.add(widgetItem);
+                currentRowWidth += containerWidth;
             } else {
                 widgetItemsAtRow = new ArrayList<>();
                 widgetItemsTable.add(widgetItemsAtRow);
                 widgetItemsAtRow.add(widgetItem);
+                containerSizeForRow = containerSize;
+                currentRowWidth = containerWidth;
             }
         }
         return widgetItemsTable;
diff --git a/src/com/android/quickstep/views/RecentsViewContainer.java b/src/com/android/quickstep/views/RecentsViewContainer.java
new file mode 100644
index 0000000..0c3f4f1
--- /dev/null
+++ b/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.LocusId;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+
+import com.android.launcher3.BaseActivity;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.ScrimView;
+
+/**
+ * Interface to be implemented by the parent view of RecentsView
+ */
+public interface RecentsViewContainer extends ActivityContext {
+
+    /**
+     * Returns an instance of an implementation of RecentsViewContainer
+     * @param context will find instance of recentsViewContainer from given context.
+     */
+    static <T extends RecentsViewContainer> T containerFromContext(Context context) {
+        if (context instanceof RecentsViewContainer) {
+            return (T) context;
+        } else if (context instanceof ContextWrapper) {
+            return containerFromContext(((ContextWrapper) context).getBaseContext());
+        } else {
+            throw new IllegalArgumentException("Cannot find RecentsViewContainer in parent tree");
+        }
+    }
+
+    /**
+     * Returns {@link SystemUiController} to manage various window flags to control system UI.
+     */
+    SystemUiController getSystemUiController();
+
+    /**
+     * Returns {@link ScrimView}
+     */
+    ScrimView getScrimView();
+
+    /**
+     * Returns the Overview Panel as a View
+     */
+    <T extends View> T getOverviewPanel();
+
+    /**
+     * Returns the RootView
+     */
+    View getRootView();
+
+    /**
+     * Dispatches a generic motion event to the view hierarchy.
+     * Returns the current RecentsViewContainer as context
+     */
+    default Context asContext() {
+        return (Context) this;
+    }
+
+    /**
+     * @see Window.Callback#dispatchGenericMotionEvent(MotionEvent)
+     */
+    boolean dispatchGenericMotionEvent(MotionEvent ev);
+
+    /**
+     * @see Window.Callback#dispatchKeyEvent(KeyEvent)
+     */
+    boolean dispatchKeyEvent(KeyEvent ev);
+
+    /**
+     * Returns overview actions view as a view
+     */
+    View getActionsView();
+
+    /**
+     * @see BaseActivity#addForceInvisibleFlag(int)
+     * @param flag {@link BaseActivity.InvisibilityFlags}
+     */
+    void addForceInvisibleFlag(@BaseActivity.InvisibilityFlags int flag);
+
+    /**
+     * @see BaseActivity#clearForceInvisibleFlag(int)
+     * @param flag {@link BaseActivity.InvisibilityFlags}
+     */
+    void clearForceInvisibleFlag(@BaseActivity.InvisibilityFlags int flag);
+
+    /**
+     * @see android.app.Activity#setLocusContext(LocusId, Bundle)
+     * @param id {@link LocusId}
+     * @param bundle {@link Bundle}
+     */
+    void setLocusContext(LocusId id, Bundle bundle);
+
+    /**
+     * @see BaseActivity#isStarted()
+     * @return boolean
+     */
+    boolean isStarted();
+
+    /**
+     * @see BaseActivity#addEventCallback(int, Runnable)
+     * @param event {@link BaseActivity.ActivityEvent}
+     * @param callback runnable to be executed upon event
+     */
+    void addEventCallback(@BaseActivity.ActivityEvent int event, Runnable callback);
+
+    /**
+     * @see BaseActivity#removeEventCallback(int, Runnable)
+     * @param event {@link BaseActivity.ActivityEvent}
+     * @param callback runnable to be executed upon event
+     */
+    void removeEventCallback(@BaseActivity.ActivityEvent int event, Runnable callback);
+
+    /**
+     * @see com.android.quickstep.util.TISBindHelper#runOnBindToTouchInteractionService(Runnable)
+     * @param r runnable to be executed upon event
+     */
+    void runOnBindToTouchInteractionService(Runnable r);
+
+    /**
+     * @see Activity#getWindow()
+     * @return Window
+     */
+    Window getWindow();
+
+    /**
+     * @see
+     * BaseActivity#addMultiWindowModeChangedListener(BaseActivity.MultiWindowModeChangedListener)
+     * @param listener {@link BaseActivity.MultiWindowModeChangedListener}
+     */
+    void addMultiWindowModeChangedListener(
+            BaseActivity.MultiWindowModeChangedListener listener);
+
+    /**
+     * @see
+     * BaseActivity#removeMultiWindowModeChangedListener(
+     * BaseActivity.MultiWindowModeChangedListener)
+     * @param listener {@link BaseActivity.MultiWindowModeChangedListener}
+     */
+    void removeMultiWindowModeChangedListener(
+            BaseActivity.MultiWindowModeChangedListener listener);
+
+    /**
+     * Begins transition from overview back to homescreen
+     */
+    void returnToHomescreen();
+}
diff --git a/src_build_config/com/android/launcher3/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java
index 3841969..6d4f56d 100644
--- a/src_build_config/com/android/launcher3/BuildConfig.java
+++ b/src_build_config/com/android/launcher3/BuildConfig.java
@@ -35,4 +35,9 @@
      * Flag to control various developer centric features
      */
     public static final boolean IS_DEBUG_DEVICE = false;
+
+    // Flag to control widgets support in Launcher
+    public static final boolean WIDGETS_ENABLED = true;
+    // Flag to control notification dots support in Launcher
+    public static final boolean NOTIFICATION_DOTS_ENABLED = true;
 }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java
similarity index 100%
rename from src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
rename to src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java b/src_no_quickstep/com/android/launcher3/uioverrides/states/OverviewState.java
similarity index 100%
rename from src_ui_overrides/com/android/launcher3/uioverrides/states/OverviewState.java
rename to src_no_quickstep/com/android/launcher3/uioverrides/states/OverviewState.java
diff --git a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
index af4f22c..6452ea2 100644
--- a/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/CustomWidgetPlugin.java
@@ -39,13 +39,16 @@
 
     /**
      * Get the UUID for the custom widget.
+     *
+     * @deprecated Not used
      */
-    String getId();
+    @Deprecated
+    default String getId() {
+        return "";
+    }
 
     /**
      * Used to modify a widgets' info.
      */
-    default void updateWidgetInfo(AppWidgetProviderInfo info, Context context) {
-
-    }
+    default void updateWidgetInfo(AppWidgetProviderInfo info, Context context) { }
 }
diff --git a/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java b/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java
new file mode 100644
index 0000000..e327648
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/NetworkFetcherPlugin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Implement this plugin to proxy network requests
+ */
+@ProvidesInterface(action = NetworkFetcherPlugin.ACTION, version = NetworkFetcherPlugin.VERSION)
+public interface NetworkFetcherPlugin extends Plugin {
+    String ACTION = "com.android.systemui.action.PLUGIN_NETWORK_FETCHER_ACTIONS";
+    int VERSION = 1;
+
+    /** Fetches the provided user and return all byte contents */
+    byte[] fetchUrl(String url) throws Exception;
+}
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index 54cc0bc..a940774 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -15,6 +15,8 @@
  */
 package com.android.systemui.plugins.shared;
 
+import android.view.MotionEvent;
+
 import java.io.PrintWriter;
 
 /**
@@ -47,7 +49,11 @@
 
     default void onActivityDestroyed() { }
 
-    interface LauncherOverlay {
+    /**
+     * @deprecated use LauncherOverlayTouchProxy directly
+     */
+    @Deprecated
+    interface LauncherOverlay extends LauncherOverlayTouchProxy {
 
         /**
          * Touch interaction leading to overscroll has begun
@@ -70,6 +76,38 @@
          * @param callbacks A set of callbacks provided by Launcher in relation to the overlay
          */
         void setOverlayCallbacks(LauncherOverlayCallbacks callbacks);
+
+        @Override
+        default void onFlingVelocity(float velocity) { }
+
+        @Override
+        default void onOverlayMotionEvent(MotionEvent ev, float scrollProgress) {
+            switch (ev.getAction()) {
+                case MotionEvent.ACTION_DOWN ->  onScrollInteractionBegin();
+                case MotionEvent.ACTION_MOVE -> onScrollChange(scrollProgress, false);
+                case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> onScrollInteractionEnd();
+            }
+
+        }
+    }
+
+    interface LauncherOverlayTouchProxy {
+
+        /**
+         * Called just before finishing scroll interaction to indicate the fling velocity
+         */
+        void onFlingVelocity(float velocity);
+
+        /**
+         * Called to dispatch various motion events to the overlay
+         */
+        void onOverlayMotionEvent(MotionEvent ev, float scrollProgress);
+
+        /**
+         * Called when the launcher is ready to use the overlay
+         * @param callbacks A set of callbacks provided by Launcher in relation to the overlay
+         */
+        default void setOverlayCallbacks(LauncherOverlayCallbacks callbacks) { }
     }
 
     interface LauncherOverlayCallbacks {
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java b/src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java
deleted file mode 100644
index 7e73ab5..0000000
--- a/src_shortcuts_overrides/com/android/launcher3/model/LauncherBinder.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.model;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Binds the results of {@link com.android.launcher3.model.LoaderTask} to the Callbacks objects.
- */
-public class LauncherBinder extends BaseLauncherBinder {
-
-    public LauncherBinder(LauncherAppState app, BgDataModel dataModel,
-            AllAppsList allAppsList, Callbacks[] callbacks) {
-        super(app, dataModel, allAppsList, callbacks, MAIN_EXECUTOR);
-    }
-
-    @Override
-    public void bindDeepShortcuts() {
-        final HashMap<ComponentKey, Integer> shortcutMapCopy;
-        synchronized (mBgDataModel) {
-            shortcutMapCopy = new HashMap<>(mBgDataModel.deepShortcutMap);
-        }
-        executeCallbacksTask(c -> c.bindDeepShortcutMap(shortcutMapCopy), mUiExecutor);
-    }
-
-    @Override
-    public void bindWidgets() {
-        final List<WidgetsListBaseEntry> widgets =
-                mBgDataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
-        executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
-    }
-
-    @Override
-    public void bindSmartspaceWidget() {
-        executeCallbacksTask(c -> c.bindSmartspaceWidget(), mUiExecutor);
-    }
-}
diff --git a/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java b/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java
deleted file mode 100644
index 968b281..0000000
--- a/src_shortcuts_overrides/com/android/launcher3/util/AbsGridOccupancy.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-/**
- * Defines method to find the next vacant cell on a grid.
- * This uses the default top-down, left-right approach and can be over-written through
- * code swaps in different launchers.
- */
-public abstract class AbsGridOccupancy {
-    /**
-     * Find the first vacant cell, if there is one.
-     *
-     * @param vacantOut Holds the x and y coordinate of the vacant cell
-     * @param spanX Horizontal cell span.
-     * @param spanY Vertical cell span.
-     *
-     * @return true if a vacant cell was found
-     */
-    protected boolean findVacantCell(int[] vacantOut, boolean[][] cells, int countX, int countY,
-            int spanX, int spanY) {
-        for (int y = 0; (y + spanY) <= countY; y++) {
-            for (int x = 0; (x + spanX) <= countX; x++) {
-                boolean available = !cells[x][y];
-                out:
-                for (int i = x; i < x + spanX; i++) {
-                    for (int j = y; j < y + spanY; j++) {
-                        available = available && !cells[i][j];
-                        if (!available) break out;
-                    }
-                }
-                if (available) {
-                    vacantOut[0] = x;
-                    vacantOut[1] = y;
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
deleted file mode 100644
index fe5c1fd..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import android.app.ActivityOptions;
-import android.app.Person;
-import android.content.Context;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.ShortcutInfo;
-import android.graphics.drawable.ColorDrawable;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.ArrayMap;
-
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.UserIconInfo;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A wrapper for the hidden API calls
- */
-public class ApiWrapper {
-
-    public static final boolean TASKBAR_DRAWN_IN_PROCESS = false;
-
-    public static Person[] getPersons(ShortcutInfo si) {
-        return Utilities.EMPTY_PERSON_ARRAY;
-    }
-
-    public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
-        return Collections.emptyMap();
-    }
-
-    /**
-     * Creates an ActivityOptions to play fade-out animation on closing targets
-     */
-    public static ActivityOptions createFadeOutAnimOptions(Context context) {
-        return ActivityOptions.makeCustomAnimation(context, 0, android.R.anim.fade_out);
-    }
-
-    /**
-     * Returns a map of all users on the device to their corresponding UI properties
-     */
-    public static Map<UserHandle, UserIconInfo> queryAllUsers(Context context) {
-        UserManager um = context.getSystemService(UserManager.class);
-        Map<UserHandle, UserIconInfo> users = new ArrayMap<>();
-        List<UserHandle> usersActual = um.getUserProfiles();
-        if (usersActual != null) {
-            for (UserHandle user : usersActual) {
-                long serial = um.getSerialNumberForUser(user);
-
-                // Simple check to check if the provided user is work profile
-                // TODO: Migrate to a better platform API
-                NoopDrawable d = new NoopDrawable();
-                boolean isWork = (d != context.getPackageManager().getUserBadgedIcon(d, user));
-                UserIconInfo info = new UserIconInfo(
-                        user,
-                        isWork ? UserIconInfo.TYPE_WORK : UserIconInfo.TYPE_MAIN,
-                        serial);
-                users.put(user, info);
-            }
-        }
-        return users;
-    }
-
-    private static class NoopDrawable extends ColorDrawable {
-        @Override
-        public int getIntrinsicHeight() {
-            return 1;
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return 1;
-        }
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PredictedAppIconInflater.java b/src_ui_overrides/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
deleted file mode 100644
index 4893c17..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/PredictedAppIconInflater.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-
-/** A util class that inflates a predicted app icon */
-public class PredictedAppIconInflater {
-    public static View inflate(LayoutInflater inflater, ViewGroup parent, WorkspaceItemInfo info) {
-        return null;
-    }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
deleted file mode 100644
index 6afa446..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.uioverrides.flags;
-
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-
-/**
- * Place holder class for developer options.
- */
-public class DeveloperOptionsUI {
-
-    public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) { }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
deleted file mode 100644
index eb0494e..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.flags;
-
-import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
-
-import com.android.launcher3.config.FeatureFlags.BooleanFlag;
-import com.android.launcher3.config.FeatureFlags.FlagState;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
-
-import java.io.PrintWriter;
-
-/**
- * Helper class to create various flags for launcher build. The base implementation does
- * not provide any flagging system, and simply replies with the default value.
- */
-public class FlagsFactory {
-
-    /**
-     * Creates a new debug flag
-     */
-    public static BooleanFlag getDebugFlag(
-            int bugId, String key, FlagState flagState, String description) {
-        return new BooleanFlag(flagState == ENABLED);
-    }
-
-    /**
-     * Creates a new debug flag
-     */
-    public static BooleanFlag getReleaseFlag(
-            int bugId, String key, FlagState flagState, String description) {
-        return new BooleanFlag(flagState == ENABLED);
-    }
-
-    /**
-     * Creates a new integer flag. Integer flags are always release flags
-     */
-    public static IntFlag getIntFlag(
-            int bugId, String key, int defaultValueInCode, String description) {
-        return new IntFlag(defaultValueInCode);
-    }
-
-    /**
-     * Dumps the current flags state to the print writer
-     */
-    public static void dump(PrintWriter pw) { }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
deleted file mode 100644
index e1a35c9..0000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.launcher3.uioverrides.plugins;
-
-import android.content.ComponentName;
-import android.content.Context;
-
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.systemui.plugins.Plugin;
-import com.android.systemui.plugins.PluginListener;
-
-import java.util.Collections;
-import java.util.Set;
-
-import androidx.preference.PreferenceDataStore;
-
-public class PluginManagerWrapper {
-
-    public static final MainThreadInitializedObject<PluginManagerWrapper> INSTANCE =
-            new MainThreadInitializedObject<>(PluginManagerWrapper::new);
-
-    private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
-    public static final String PLUGIN_CHANGED = "com.android.systemui.action.PLUGIN_CHANGED";
-
-    private PluginManagerWrapper(Context c) {
-    }
-
-    public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass) {
-    }
-
-    public void addPluginListener(PluginListener<? extends Plugin> listener, Class<?> pluginClass,
-            boolean allowMultiple) {
-    }
-
-    public void removePluginListener(PluginListener<? extends Plugin> listener) { }
-
-    public Set<String> getPluginActions() {
-        return Collections.emptySet();
-    }
-
-    public PreferenceDataStore getPluginEnabler() {
-        return new PreferenceDataStore() { };
-    }
-
-    public static String pluginEnabledKey(ComponentName cn) {
-        return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
-    }
-
-    public static boolean hasPlugins(Context context) {
-        return false;
-    }
-}
diff --git a/tests/Android.bp b/tests/Android.bp
index 84c3951..3822ff8 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -21,35 +21,22 @@
 filegroup {
     name: "launcher-tests-src",
     srcs: [
-      "src/**/*.java",
-      "src/**/*.kt"
+        "src/**/*.java",
+        "src/**/*.kt",
+        ":launcher3-robo-src",
     ],
     exclude_srcs: [
-        ":launcher-non-quickstep-tests-src"
+        ":launcher-non-quickstep-tests-src",
     ],
 }
 
-// Source code used for screenshot tests
 filegroup {
-    name: "launcher-image-tests-src",
+    name: "launcher3-robo-src",
+    // multivalentTests directory is a shared folder for not only robolectric converted test
+    // classes but also shared helper classes.
     srcs: [
-      "src/com/android/launcher3/celllayout/board/*.java",
-      "src/com/android/launcher3/celllayout/board/*.kt",
-      "src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java",
-      "src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
-      "src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
-      "src/com/android/launcher3/ui/TestViewHelpers.java",
-      "src/com/android/launcher3/util/LauncherLayoutBuilder.java",
-      "src/com/android/launcher3/util/ModelTestExtensions.kt",
-      "src/com/android/launcher3/util/TestConstants.java",
-      "src/com/android/launcher3/util/TestUtil.java",
-      "src/com/android/launcher3/util/Wait.java",
-      "src/com/android/launcher3/util/WidgetUtils.java",
-      "src/com/android/launcher3/util/rule/*.java",
-      "src/com/android/launcher3/util/rule/*.kt",
-      "src/com/android/launcher3/util/viewcapture_analysis/*.java",
-      "src/com/android/launcher3/testcomponent/*.java",
-      "src/com/android/launcher3/testcomponent/*.kt",
+        "multivalentTests/src/**/*.java",
+        "multivalentTests/src/**/*.kt",
     ],
 }
 
@@ -57,8 +44,8 @@
 filegroup {
     name: "launcher-non-quickstep-tests-src",
     srcs: [
-       "src/com/android/launcher3/nonquickstep/**/*.java",
-       "src/com/android/launcher3/nonquickstep/**/*.kt",
+        "src/com/android/launcher3/nonquickstep/**/*.java",
+        "src/com/android/launcher3/nonquickstep/**/*.kt",
     ],
 }
 
@@ -66,42 +53,22 @@
 filegroup {
     name: "launcher-oop-tests-src",
     srcs: [
-      "src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java",
-      "src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java",
-      "src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java",
-      "src/com/android/launcher3/dragging/TaplDragTest.java",
-      "src/com/android/launcher3/dragging/TaplUninstallRemove.java",
-      "src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
-      "src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
-      "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
-      "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
-      "src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
-      "src/com/android/launcher3/util/LauncherLayoutBuilder.java",
-      "src/com/android/launcher3/util/TestConstants.java",
-      "src/com/android/launcher3/util/TestUtil.java",
-      "src/com/android/launcher3/util/Wait.java",
-      "src/com/android/launcher3/util/WidgetUtils.java",
-      "src/com/android/launcher3/util/rule/FailureWatcher.java",
-      "src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
-      "src/com/android/launcher3/util/rule/SamplerRule.java",
-      "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
-      "src/com/android/launcher3/util/rule/ShellCommandRule.java",
-      "src/com/android/launcher3/util/rule/TestIsolationRule.java",
-      "src/com/android/launcher3/util/rule/TestStabilityRule.java",
-      "src/com/android/launcher3/util/viewcapture_analysis/*.java",
-      "src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
-      "src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
-      "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
-      "src/com/android/launcher3/testcomponent/TestCommandReceiver.java",
-      "src/com/android/launcher3/testcomponent/TestLauncherActivity.java",
-      "src/com/android/launcher3/testcomponent/ImeTestActivity.java",
+        ":launcher-testing-helpers",
+        "src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java",
+        "src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java",
+        "src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java",
+        "src/com/android/launcher3/dragging/TaplDragTest.java",
+        "src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java",
+        "src/com/android/launcher3/ui/TaplTestsLauncher3Test.java",
+        "src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java",
+        "src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java",
     ],
 }
 
 // Library with all the dependencies for building quickstep
 android_library {
     name: "Launcher3TestLib",
-    srcs: [ ],
+    srcs: [],
     asset_dirs: ["assets"],
     resource_dirs: ["res"],
     static_libs: [
@@ -119,18 +86,24 @@
         "mockito-target-extended-minus-junit4",
         "launcher_log_protos_lite",
         "truth",
+        "kotlinx_coroutines_test",
         "platform-test-rules",
         "testables",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
+        "android.appwidget.flags-aconfig-java",
     ],
     manifest: "AndroidManifest-common.xml",
     platform_apis: true,
+    // TODO(b/319712088): re-enable use_resource_processor
+    use_resource_processor: false,
 }
 
 android_library {
     name: "Launcher3TestResources",
     resource_dirs: ["res"],
+    // TODO(b/319712088): re-enable use_resource_processor
+    use_resource_processor: false,
 }
 
 android_test {
@@ -167,10 +140,75 @@
 android_library {
     name: "launcher-testing-shared",
     srcs: [
-        "shared/com/android/launcher3/testing/shared/**/*.java"
+        "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.java",
+        "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.kt",
     ],
-    resource_dirs: [ ],
-    manifest: "shared/AndroidManifest.xml",
+    resource_dirs: [],
+    manifest: "multivalentTests/shared/AndroidManifest.xml",
     sdk_version: "current",
     min_sdk_version: min_launcher3_sdk_version,
- }
+}
+
+filegroup {
+    name: "launcher-testing-helpers",
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt",
+        "multivalentTests/src/**/*.java",
+        "multivalentTests/src/**/*.kt",
+        "src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+        "tapl/com/android/launcher3/tapl/*.java",
+        "tapl/com/android/launcher3/tapl/*.kt",
+    ],
+    exclude_srcs: [
+        // Test classes
+        "src/**/*Test.java",
+        "src/**/*Test.kt",
+        "multivalentTests/src/**/*Test.java",
+        "multivalentTests/src/**/*Test.kt",
+    ],
+}
+
+android_robolectric_test {
+    enabled: true,
+    name: "Launcher3RoboTests",
+    srcs: [
+        ":launcher3-robo-src",
+
+        // Test util classes
+        ":launcher-testing-helpers",
+        ":launcher-testing-shared",
+    ],
+    exclude_srcs: [
+        //"src/com/android/launcher3/util/CellContentDimensionsTest.kt", // Failing - b/316553889
+
+        // requires modification to work with inline mock maker
+        "src/com/android/launcher3/util/rule/StaticMockitoRule.java",
+    ],
+    java_resource_dirs: ["config"],
+    static_libs: [
+        "flag-junit-base",
+        "com_android_launcher3_flags_lib",
+        "com_android_wm_shell_flags_lib",
+        "androidx.test.uiautomator_uiautomator",
+        "androidx.core_core-animation-testing",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "uiautomator-helpers",
+        "mockito-robolectric-prebuilt",
+        "mockito-kotlin2",
+        "platform-parametric-runner-lib",
+        "testables",
+        "Launcher3TestResources",
+        "SystemUISharedLib",
+        "launcher-testing-shared",
+    ],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "android.test.mock",
+        "truth",
+    ],
+    instrumentation_for: "Launcher3",
+    upstream: true,
+}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index bd9da0a..a9b75ea 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -88,6 +88,14 @@
                 android:resource="@xml/appwidget_dynamic_colors"/>
         </receiver>
 
+        <receiver android:name="com.android.launcher3.testcomponent.UnarchiveBroadcastReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.UNARCHIVE_PACKAGE"/>
+            </intent-filter>
+        </receiver>
+
         <activity
             android:name="com.android.launcher3.testcomponent.WidgetConfigActivity"
             android:exported="true">
@@ -149,7 +157,8 @@
             android:name="com.android.launcher3.testcomponent.BaseTestingActivity"
             android:label="LauncherTestApp"
             android:exported="true"
-            android:taskAffinity="com.android.launcher3.testcomponent.Affinity1">
+            android:taskAffinity="com.android.launcher3.testcomponent.Affinity1"
+            android:theme="@style/Theme.TestActivities">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
@@ -292,6 +301,33 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity-alias>
+        <activity-alias android:name="SplitTask1"
+            android:label="1st TopLeft"
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
+        <activity-alias android:name="SplitTask2"
+            android:label="2nd BottomRight"
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
+        <activity-alias android:name="ActivityNoLabel"
+            android:label=""
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
         <activity-alias android:name="MaxShortcutsActivity"
             android:label="TestActivityMaxShortcuts"
             android:exported="true"
@@ -343,6 +379,33 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity-alias>
+        <activity-alias android:name="AAAActivity"
+            android:label="AAA"
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
+        <activity-alias android:name="ZZZActivity"
+            android:label="ZZZ"
+            android:exported="true"
+            android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity-alias>
+        <activity android:name="com.android.launcher3.testcomponent.ExcludeFromRecentsTestActivity"
+            android:label="ExcludeFromRecentsTestActivity"
+            android:exported="true"
+            android:excludeFromRecents="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
 
         <!-- [b/197780098] Disable eager initialization of Jetpack libraries. -->
         <provider
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 0aed1e1..29c34be 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -13,14 +13,27 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<!-- This test config file is auto-generated. -->
+
 <configuration description="Runs Launcher3 tests.">
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
 
+    <option name="max-tmp-logcat-file" value="104857600" /> <!-- 100 * 1024 * 1024 -->
+
+    <logger class="com.android.tradefed.log.FileLogger">
+        <option name="max-log-size" value="20" />
+    </logger>
+
+    <!-- Disables the "Ramdump uploader to betterbug" -->
+    <option name="post-boot-command" value="am broadcast --async --user 0 -a com.google.gservices.intent.action.GSERVICES_OVERRIDE -e betterbug_enable_ramdump_uploader false" />
+
     <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
         <option name="set-test-harness" value="true" />
-        <option name="run-command" value="am force-stop com.android.launcher3" />
+
+        <option name="run-command" value="svc nfc disable" />
+        <option name="run-command" value="settings put global ble_scan_always_enabled 0" />
+        <option name="run-command" value="svc bluetooth disable" />
+
         <option name="run-command" value="pm uninstall com.google.android.apps.nexuslauncher" />
         <option name="run-command" value="pm uninstall com.google.android.apps.nexuslauncher.out_of_proc_tests" />
         <option name="run-command" value="pm uninstall com.google.android.apps.nexuslauncher.tests" />
@@ -30,6 +43,9 @@
         <option name="run-command" value="settings delete secure assistant" />
         <option name="run-command" value="settings put global airplane_mode_on 1" />
         <option name="run-command" value="am broadcast -a android.intent.action.AIRPLANE_MODE" />
+
+        <option name="run-command" value="settings put system pointer_location 1" />
+        <option name="run-command" value="settings put system show_touches 1" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
@@ -46,6 +62,6 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.launcher3.tests" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
-        <option name="instrumentation-arg" key="waitForActivitiesToComplete" value="false" />
+        <option name="hidden-api-checks" value="false" />
     </test>
 </configuration>
diff --git a/tests/assets/databases/BackupAndRestore/launcher.db b/tests/assets/databases/BackupAndRestore/launcher.db
new file mode 100644
index 0000000..126d166
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db b/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db
new file mode 100644
index 0000000..6d8cd73
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_3_by_3.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db b/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db
new file mode 100644
index 0000000..00061dd
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_4_by_4.db
Binary files differ
diff --git a/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db b/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db
new file mode 100644
index 0000000..e2e65aa
--- /dev/null
+++ b/tests/assets/databases/BackupAndRestore/launcher_4_by_5.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
new file mode 100644
index 0000000..8bea3ce
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to3x3.db b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
new file mode 100644
index 0000000..686056d
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to4x7.db b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
new file mode 100644
index 0000000..cd105c5
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
new file mode 100644
index 0000000..4b46969
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/test_launcher.db b/tests/assets/databases/GridMigrationTest/test_launcher.db
new file mode 100644
index 0000000..c680e95
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/test_launcher.db
Binary files differ
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index 18752e9..82a6310 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 273.0px (104.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1927.0px (734.0952dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.7781155px (0.29642496dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.7666667px (0.2920635dp)
 	getCellLayoutHeight(): 1974.0px (752.0dp)
 	getCellLayoutWidth(): 1080.0px (411.42856dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index c0de8d8..4271105 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 294.0px (112.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 147.0px (56.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1906.0px (726.0952dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.77572966px (0.29551607dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.76666665px (0.29206347dp)
 	getCellLayoutHeight(): 1953.0px (744.0dp)
 	getCellLayoutWidth(): 1080.0px (411.42856dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index 920ba6f..8bd6b99 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 252.0px (96.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 0.0px (0.0dp)
 	mHotseatBarEdgePaddingPx: 63.0px (24.0dp)
@@ -80,8 +81,8 @@
 	hotseatQsbSpace: 0.0px (0.0dp)
 	hotseatQsbHeight: 0.0px (0.0dp)
 	springLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)
-	getHotseatLayoutPadding(context).top: 64.0px (24.380953dp)
-	getHotseatLayoutPadding(context).bottom: 112.0px (42.666668dp)
+	getHotseatLayoutPadding(context).top: 74.0px (28.190475dp)
+	getHotseatLayoutPadding(context).bottom: 103.0px (39.238094dp)
 	getHotseatLayoutPadding(context).left: 42.0px (16.0dp)
 	getHotseatLayoutPadding(context).right: 63.0px (24.0dp)
 	numShownHotseatIcons: 5
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -123,8 +123,8 @@
 	dropTargetBarSizePx: 95.0px (36.190475dp)
 	dropTargetBarBottomMarginPx: 16.0px (6.095238dp)
 	getCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)
-	getCellLayoutSpringLoadShrunkBottom(): 952.0px (362.66666dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.79639447px (0.30338836dp)
+	getCellLayoutSpringLoadShrunkBottom(): 961.0px (366.09525dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.8059385px (0.30702418dp)
 	getCellLayoutHeight(): 943.0px (359.2381dp)
 	getCellLayoutWidth(): 2073.0px (789.7143dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index 65460ec..8dbb413 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 0.0px (0.0dp)
 	allAppsLeftRightMargin: 0.0px (0.0dp)
 	hotseatBarSizePx: 252.0px (96.0dp)
-	inv.hotseatColumnSpan: 5
+	mHotseatColumnSpan: 5
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 166.0px (63.238094dp)
 	hotseatBarBottomSpacePx: 0.0px (0.0dp)
 	mHotseatBarEdgePaddingPx: 63.0px (24.0dp)
@@ -80,8 +81,8 @@
 	hotseatQsbSpace: 0.0px (0.0dp)
 	hotseatQsbHeight: 0.0px (0.0dp)
 	springLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)
-	getHotseatLayoutPadding(context).top: 64.0px (24.380953dp)
-	getHotseatLayoutPadding(context).bottom: 49.0px (18.666666dp)
+	getHotseatLayoutPadding(context).top: 74.0px (28.190475dp)
+	getHotseatLayoutPadding(context).bottom: 40.0px (15.238095dp)
 	getHotseatLayoutPadding(context).left: 42.0px (16.0dp)
 	getHotseatLayoutPadding(context).right: 189.0px (72.0dp)
 	numShownHotseatIcons: 5
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -123,8 +123,8 @@
 	dropTargetBarSizePx: 95.0px (36.190475dp)
 	dropTargetBarBottomMarginPx: 16.0px (6.095238dp)
 	getCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)
-	getCellLayoutSpringLoadShrunkBottom(): 1008.0px (384.0dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.8021869px (0.305595dp)
+	getCellLayoutSpringLoadShrunkBottom(): 1017.0px (387.42856dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.8111332px (0.3090031dp)
 	getCellLayoutHeight(): 1006.0px (383.2381dp)
 	getCellLayoutWidth(): 1947.0px (741.7143dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index 1781673..ab4b286 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
-	allAppsShiftRange: 1496.0px (748.0dp)
+	allAppsShiftRange: 1600.0px (800.0dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 120.0px (60.0dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 412.0px (206.0dp)
 	hotseatBarSizePx: 200.0px (100.0dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1960.0px (980.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 80.0px (40.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -82,12 +83,12 @@
 	springLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)
-	getHotseatLayoutPadding(context).left: 668.0px (334.0dp)
-	getHotseatLayoutPadding(context).right: 668.0px (334.0dp)
+	getHotseatLayoutPadding(context).left: 300.0px (150.0dp)
+	getHotseatLayoutPadding(context).right: 300.0px (150.0dp)
 	numShownHotseatIcons: 6
-	hotseatBorderSpace: 100.0px (50.0dp)
+	hotseatBorderSpace: 248.0px (124.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1224.0px (612.0dp)
+	hotseatQsbWidth: 1950.0px (975.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 64.0px (32.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)
 	getCellLayoutHeight(): 1252.0px (626.0dp)
 	getCellLayoutWidth(): 2198.0px (1099.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index bd9e267..80835bc 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
-	allAppsShiftRange: 1496.0px (748.0dp)
+	allAppsShiftRange: 1600.0px (800.0dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 120.0px (60.0dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 412.0px (206.0dp)
 	hotseatBarSizePx: 200.0px (100.0dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1960.0px (980.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 80.0px (40.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -82,12 +83,12 @@
 	springLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)
-	getHotseatLayoutPadding(context).left: 668.0px (334.0dp)
-	getHotseatLayoutPadding(context).right: 668.0px (334.0dp)
+	getHotseatLayoutPadding(context).left: 300.0px (150.0dp)
+	getHotseatLayoutPadding(context).right: 300.0px (150.0dp)
 	numShownHotseatIcons: 6
-	hotseatBorderSpace: 100.0px (50.0dp)
+	hotseatBorderSpace: 248.0px (124.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1224.0px (612.0dp)
+	hotseatQsbWidth: 1950.0px (975.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 64.0px (32.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)
 	getCellLayoutHeight(): 1252.0px (626.0dp)
 	getCellLayoutWidth(): 2198.0px (1099.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index e983ef7..fc53107 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -50,12 +50,12 @@
 	folderContentPaddingLeftRight: 0.0px (0.0dp)
 	folderTopPadding: 48.0px (24.0dp)
 	folderFooterHeight: 112.0px (56.0dp)
-	bottomSheetTopPadding: 704.0px (352.0dp)
+	bottomSheetTopPadding: 530.0px (265.0dp)
 	bottomSheetOpenDuration: 500
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
-	allAppsShiftRange: 2019.0px (1009.5dp)
+	allAppsShiftRange: 2560.0px (1280.0dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 120.0px (60.0dp)
@@ -66,12 +66,13 @@
 	allAppsBorderSpacePxX: 16.0px (8.0dp)
 	allAppsBorderSpacePxY: 32.0px (16.0dp)
 	numShownAllAppsColumns: 6
-	allAppsPadding.top: 541.0px (270.5dp)
+	allAppsPadding.top: 104.0px (52.0dp)
 	allAppsPadding.left: 32.0px (16.0dp)
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 152.0px (76.0dp)
 	hotseatBarSizePx: 272.0px (136.0dp)
-	inv.hotseatColumnSpan: 6
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1300.0px (650.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 152.0px (76.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -87,7 +88,7 @@
 	numShownHotseatIcons: 6
 	hotseatBorderSpace: 116.0px (58.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1300.0px (650.0dp)
+	hotseatQsbWidth: 1290.0px (645.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 96.0px (48.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)
 	getCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)
 	getCellLayoutHeight(): 1856.0px (928.0dp)
 	getCellLayoutWidth(): 1528.0px (764.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index aa92838..836819f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -50,12 +50,12 @@
 	folderContentPaddingLeftRight: 0.0px (0.0dp)
 	folderTopPadding: 48.0px (24.0dp)
 	folderFooterHeight: 112.0px (56.0dp)
-	bottomSheetTopPadding: 704.0px (352.0dp)
+	bottomSheetTopPadding: 530.0px (265.0dp)
 	bottomSheetOpenDuration: 500
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 0.0
-	allAppsShiftRange: 2019.0px (1009.5dp)
+	allAppsShiftRange: 2560.0px (1280.0dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 120.0px (60.0dp)
@@ -66,12 +66,13 @@
 	allAppsBorderSpacePxX: 16.0px (8.0dp)
 	allAppsBorderSpacePxY: 32.0px (16.0dp)
 	numShownAllAppsColumns: 6
-	allAppsPadding.top: 541.0px (270.5dp)
+	allAppsPadding.top: 104.0px (52.0dp)
 	allAppsPadding.left: 32.0px (16.0dp)
 	allAppsPadding.right: 32.0px (16.0dp)
 	allAppsLeftRightMargin: 152.0px (76.0dp)
 	hotseatBarSizePx: 272.0px (136.0dp)
-	inv.hotseatColumnSpan: 6
+	mHotseatColumnSpan: 6
+	mHotseatWidthPx: 1300.0px (650.0dp)
 	hotseatCellHeightPx: 135.0px (67.5dp)
 	hotseatBarBottomSpacePx: 152.0px (76.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -87,7 +88,7 @@
 	numShownHotseatIcons: 6
 	hotseatBorderSpace: 116.0px (58.0dp)
 	isQsbInline: false
-	hotseatQsbWidth: 1300.0px (650.0dp)
+	hotseatQsbWidth: 1290.0px (645.0dp)
 	isTaskbarPresent:false
 	isTaskbarPresentInApps:true
 	taskbarHeight: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 96.0px (48.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)
 	getCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)
 	getCellLayoutHeight(): 1856.0px (928.0dp)
 	getCellLayoutWidth(): 1528.0px (764.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index 43e4a60..108182f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 1.0
-	allAppsShiftRange: 1730.0px (659.0476dp)
+	allAppsShiftRange: 1840.0px (700.9524dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 141.0px (53.714287dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 183.0px (69.71429dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)
 	getCellLayoutHeight(): 1370.0px (521.9048dp)
 	getCellLayoutWidth(): 1083.0px (412.57144dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index e7ea839..313d2a3 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 1.0
-	allAppsShiftRange: 1730.0px (659.0476dp)
+	allAppsShiftRange: 1840.0px (700.9524dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 141.0px (53.714287dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 183.0px (69.71429dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -124,7 +124,7 @@
 	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
 	getCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)
 	getCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
 	getWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)
 	getCellLayoutHeight(): 1370.0px (521.9048dp)
 	getCellLayoutWidth(): 1083.0px (412.57144dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 043380c..fb392a8 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 1.0
-	allAppsShiftRange: 2075.0px (790.4762dp)
+	allAppsShiftRange: 2208.0px (841.1429dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 141.0px (53.714287dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 1.0px (0.3809524dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -79,7 +80,7 @@
 	hotseatBarEndOffset: 0.0px (0.0dp)
 	hotseatQsbSpace: 0.0px (0.0dp)
 	hotseatQsbHeight: 0.0px (0.0dp)
-	springLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)
+	springLoadedHotseatBarTopMarginPx: 168.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)
 	getHotseatLayoutPadding(context).left: 98.0px (37.333332dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -119,12 +119,12 @@
 	overviewPageSpacing: 0.0px (0.0dp)
 	overviewRowSpacing: 0.0px (0.0dp)
 	overviewGridSideMargin: 0.0px (0.0dp)
-	dropTargetBarTopMarginPx: 168.0px (64.0dp)
+	dropTargetBarTopMarginPx: 0.0px (0.0dp)
 	dropTargetBarSizePx: 147.0px (56.0dp)
-	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
-	getCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)
-	getCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)
+	dropTargetBarBottomMarginPx: 84.0px (32.0dp)
+	getCellLayoutSpringLoadShrunkTop(): 364.0px (138.66667dp)
+	getCellLayoutSpringLoadShrunkBottom(): 1773.0px (675.4286dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.81871px (0.31188953dp)
 	getCellLayoutHeight(): 1721.0px (655.619dp)
 	getCellLayoutWidth(): 899.0px (342.4762dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index a1b3e95..2c4b3c3 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -55,7 +55,7 @@
 	bottomSheetCloseDuration: 500
 	bottomSheetWorkspaceScale: 0.97
 	bottomSheetDepth: 1.0
-	allAppsShiftRange: 2075.0px (790.4762dp)
+	allAppsShiftRange: 2208.0px (841.1429dp)
 	allAppsOpenDuration: 500
 	allAppsCloseDuration: 500
 	allAppsIconSizePx: 141.0px (53.714287dp)
@@ -71,7 +71,8 @@
 	allAppsPadding.right: 42.0px (16.0dp)
 	allAppsLeftRightMargin: 1.0px (0.3809524dp)
 	hotseatBarSizePx: 267.0px (101.71429dp)
-	inv.hotseatColumnSpan: 4
+	mHotseatColumnSpan: 4
+	mHotseatWidthPx: 0.0px (0.0dp)
 	hotseatCellHeightPx: 159.0px (60.57143dp)
 	hotseatBarBottomSpacePx: 126.0px (48.0dp)
 	mHotseatBarEdgePaddingPx: 0.0px (0.0dp)
@@ -79,7 +80,7 @@
 	hotseatBarEndOffset: 0.0px (0.0dp)
 	hotseatQsbSpace: 0.0px (0.0dp)
 	hotseatQsbHeight: 0.0px (0.0dp)
-	springLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)
+	springLoadedHotseatBarTopMarginPx: 168.0px (64.0dp)
 	getHotseatLayoutPadding(context).top: 0.0px (0.0dp)
 	getHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)
 	getHotseatLayoutPadding(context).left: 98.0px (37.333332dp)
@@ -110,7 +111,6 @@
 	overviewTaskIconSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)
-	overviewTaskIconAppChipMenuDrawableSizePx: 0.0px (0.0dp)
 	overviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)
 	overviewActionsTopMarginPx: 0.0px (0.0dp)
 	overviewActionsHeight: 0.0px (0.0dp)
@@ -119,12 +119,12 @@
 	overviewPageSpacing: 0.0px (0.0dp)
 	overviewRowSpacing: 0.0px (0.0dp)
 	overviewGridSideMargin: 0.0px (0.0dp)
-	dropTargetBarTopMarginPx: 168.0px (64.0dp)
+	dropTargetBarTopMarginPx: 0.0px (0.0dp)
 	dropTargetBarSizePx: 147.0px (56.0dp)
-	dropTargetBarBottomMarginPx: 42.0px (16.0dp)
-	getCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)
-	getCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)
-	workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
-	getWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)
+	dropTargetBarBottomMarginPx: 84.0px (32.0dp)
+	getCellLayoutSpringLoadShrunkTop(): 364.0px (138.66667dp)
+	getCellLayoutSpringLoadShrunkBottom(): 1773.0px (675.4286dp)
+	workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+	getWorkspaceSpringLoadScale(): 0.81871px (0.31188953dp)
 	getCellLayoutHeight(): 1721.0px (655.619dp)
 	getCellLayoutWidth(): 899.0px (342.4762dp)
diff --git a/tests/config/robolectric.properties b/tests/config/robolectric.properties
new file mode 100644
index 0000000..fab7251
--- /dev/null
+++ b/tests/config/robolectric.properties
@@ -0,0 +1 @@
+sdk=NEWEST_SDK
diff --git a/tests/dummy_app/Android.bp b/tests/multivalentTests/dummy_app/Android.bp
similarity index 100%
rename from tests/dummy_app/Android.bp
rename to tests/multivalentTests/dummy_app/Android.bp
diff --git a/tests/dummy_app/AndroidManifest.xml b/tests/multivalentTests/dummy_app/AndroidManifest.xml
similarity index 100%
rename from tests/dummy_app/AndroidManifest.xml
rename to tests/multivalentTests/dummy_app/AndroidManifest.xml
diff --git a/tests/dummy_app/res/layout/empty_activity.xml b/tests/multivalentTests/dummy_app/res/layout/empty_activity.xml
similarity index 100%
rename from tests/dummy_app/res/layout/empty_activity.xml
rename to tests/multivalentTests/dummy_app/res/layout/empty_activity.xml
diff --git a/tests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml b/tests/multivalentTests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
similarity index 100%
rename from tests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
rename to tests/multivalentTests/dummy_app/res/mipmap-anydpi/ic_launcher1.xml
diff --git a/tests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml b/tests/multivalentTests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
similarity index 100%
rename from tests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
rename to tests/multivalentTests/dummy_app/res/mipmap-anydpi/ic_launcher2.xml
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/ic_launcher1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png b/tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/ic_launcher2.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/icon_back_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxhdpi/icon_fore_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/ic_launcher1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png b/tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/ic_launcher2.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/icon_back_1.png
Binary files differ
diff --git a/tests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png b/tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png
similarity index 100%
rename from tests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png
rename to tests/multivalentTests/dummy_app/res/mipmap-xxxhdpi/icon_fore_1.png
Binary files differ
diff --git a/tests/dummy_app/res/values/colors.xml b/tests/multivalentTests/dummy_app/res/values/colors.xml
similarity index 100%
rename from tests/dummy_app/res/values/colors.xml
rename to tests/multivalentTests/dummy_app/res/values/colors.xml
diff --git a/tests/dummy_app/src/com/example/android/aardwolf/Activity1.java b/tests/multivalentTests/dummy_app/src/com/example/android/aardwolf/Activity1.java
similarity index 100%
rename from tests/dummy_app/src/com/example/android/aardwolf/Activity1.java
rename to tests/multivalentTests/dummy_app/src/com/example/android/aardwolf/Activity1.java
diff --git a/tests/shared/AndroidManifest.xml b/tests/multivalentTests/shared/AndroidManifest.xml
similarity index 100%
rename from tests/shared/AndroidManifest.xml
rename to tests/multivalentTests/shared/AndroidManifest.xml
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/OWNERS b/tests/multivalentTests/shared/com/android/launcher3/testing/OWNERS
new file mode 100644
index 0000000..a818d5e
--- /dev/null
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/OWNERS
@@ -0,0 +1,5 @@
+vadimt@google.com
+sunnygoyal@google.com
+winsonc@google.com
+hyunyoungs@google.com
+mateuszc@google.com
\ No newline at end of file
diff --git a/tests/shared/com/android/launcher3/testing/shared/HotseatCellCenterRequest.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/HotseatCellCenterRequest.java
similarity index 100%
rename from tests/shared/com/android/launcher3/testing/shared/HotseatCellCenterRequest.java
rename to tests/multivalentTests/shared/com/android/launcher3/testing/shared/HotseatCellCenterRequest.java
diff --git a/tests/shared/com/android/launcher3/testing/shared/ResourceUtils.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/ResourceUtils.java
similarity index 100%
rename from tests/shared/com/android/launcher3/testing/shared/ResourceUtils.java
rename to tests/multivalentTests/shared/com/android/launcher3/testing/shared/ResourceUtils.java
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestInformationRequest.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestInformationRequest.java
similarity index 100%
rename from tests/shared/com/android/launcher3/testing/shared/TestInformationRequest.java
rename to tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestInformationRequest.java
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
similarity index 87%
rename from tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
rename to tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index fcb5158..108db6c 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -101,13 +101,14 @@
     public static final String REQUEST_TASKBAR_FROM_NAV_THRESHOLD = "taskbar-from-nav-threshold";
     public static final String REQUEST_STASHED_TASKBAR_SCALE = "taskbar-stash-handle-scale";
     public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
+    public static final String REQUEST_TASKBAR_IME_DOCKED = "taskbar-ime-docked";
     public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
     public static final String REQUEST_APPS_LIST_SCROLL_Y = "apps-list-scroll-y";
     public static final String REQUEST_TASKBAR_APPS_LIST_SCROLL_Y = "taskbar-apps-list-scroll-y";
     public static final String REQUEST_WIDGETS_SCROLL_Y = "widgets-scroll-y";
     public static final String REQUEST_TARGET_INSETS = "target-insets";
     public static final String REQUEST_WINDOW_INSETS = "window-insets";
-    public static final String REQUEST_IME_INSETS = "ime-insets";
+    public static final String REQUEST_SYSTEM_GESTURE_REGION = "gesture-region";
     public static final String REQUEST_PID = "pid";
     public static final String REQUEST_FORCE_GC = "gc";
     public static final String REQUEST_RECENT_TASKS_LIST = "recent-tasks-list";
@@ -119,8 +120,13 @@
     public static final String REQUEST_CLEAR_DATA = "clear-data";
     public static final String REQUEST_HOTSEAT_ICON_NAMES = "get-hotseat-icon-names";
     public static final String REQUEST_IS_TABLET = "is-tablet";
+    public static final String REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED =
+            "is-predictive-back-swipe-enabled";
+    public static final String REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION =
+            "enable-taskbar-navbar-unification";
     public static final String REQUEST_NUM_ALL_APPS_COLUMNS = "num-all-apps-columns";
     public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
+    public static final String REQUEST_CELL_LAYOUT_BOARDER_HEIGHT = "cell-layout-boarder-height";
     public static final String REQUEST_START_DRAG_THRESHOLD = "start-drag-threshold";
     public static final String REQUEST_SHELL_DRAG_READY = "shell-drag-ready";
     public static final String REQUEST_GET_ACTIVITIES_CREATED_COUNT =
@@ -147,6 +153,9 @@
     public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
             "get-grid-task-size-rect-for-tablet";
     public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing";
+    public static final String REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX =
+            "get-overview-current-page-index";
+    public static final String REQUEST_GET_SPLIT_SELECTION_ACTIVE = "get-split-selection-active";
     public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
     public static final String REQUEST_ENABLE_SUGGESTION = "enable-suggestion";
     public static final String REQUEST_MODEL_QUEUE_CLEARED = "model-queue-cleared";
@@ -164,6 +173,12 @@
     public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
     public static final String ICON_MISSING = "b/282963545";
     public static final String OVERVIEW_OVER_HOME = "b/279059025";
+    public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
+    public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
+    public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
+    public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
+    public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
+    public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
@@ -171,6 +186,10 @@
     public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
 
     public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
+    public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
+
+    public static final String REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED =
+            "unstash-bubble-bar-if-stashed";
 
     /** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
     public static void testLogD(String tag, String message) {
diff --git a/tests/shared/com/android/launcher3/testing/shared/WorkspaceCellCenterRequest.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/WorkspaceCellCenterRequest.java
similarity index 100%
rename from tests/shared/com/android/launcher3/testing/shared/WorkspaceCellCenterRequest.java
rename to tests/multivalentTests/shared/com/android/launcher3/testing/shared/WorkspaceCellCenterRequest.java
diff --git a/tests/src/com/android/launcher3/AppWidgetsRestoredReceiverTest.kt b/tests/multivalentTests/src/com/android/launcher3/AppWidgetsRestoredReceiverTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/AppWidgetsRestoredReceiverTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/AppWidgetsRestoredReceiverTest.kt
diff --git a/tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
diff --git a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
similarity index 82%
rename from tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index fb364ad..0c3081f 100644
--- a/tests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -15,8 +15,6 @@
  */
 package com.android.launcher3.celllayout;
 
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
 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;
@@ -24,16 +22,13 @@
 
 import android.content.Context;
 
-import androidx.test.uiautomator.UiDevice;
-
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.ModelDbController;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
-import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.ModelTestExtensions;
 
@@ -64,7 +59,7 @@
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
             ModelDbController controller = model.getModelDbController();
             // Migrate any previous data so that the DB state is correct
-            controller.tryMigrateDB();
+            controller.tryMigrateDB(null /* restoreEventLogger */);
 
             // Create DB again to load fresh data
             controller.createEmptyDB();
@@ -78,9 +73,8 @@
                     ContentWriter writer = new ContentWriter(mContext);
                     ItemInfo item = mItemsToSubmit.get(i).get();
 
-                    if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
-                        FolderInfo folderInfo = (FolderInfo) item;
-                        for (ItemInfo itemInfo : folderInfo.contents) {
+                    if (item instanceof CollectionInfo ci) {
+                        for (ItemInfo itemInfo : ci.getContents()) {
                             itemInfo.container = i;
                             containerItems.add(itemInfo);
                         }
@@ -106,15 +100,4 @@
         runOnExecutorSync(MAIN_EXECUTOR, model::forceReload);
         ModelTestExtensions.INSTANCE.loadModelSync(model);
     }
-
-    /**
-     * Commits the transaction and waits for home load
-     */
-    public void commitAndLoadHome(LauncherInstrumentation inst) {
-        commit();
-
-        // Launch the home activity
-        UiDevice.getInstance(getInstrumentation()).pressHome();
-        inst.waitForLauncherInitialized();
-    }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
similarity index 96%
rename from tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
index dbbdcf5..e5ad888 100644
--- a/tests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellLayoutBoard.java
@@ -66,7 +66,7 @@
     }
 
     public CellLayoutBoard(int width, int height) {
-        mWidget = new char[width + 1][height + 1];
+        mWidget = new char[width][height];
         this.mWidth = width;
         this.mHeight = height;
         for (int x = 0; x < mWidget.length; x++) {
@@ -199,6 +199,19 @@
         return 'z';
     }
 
+    /**
+     * Check if the given area is empty.
+     */
+    public boolean isEmpty(int x, int y, int spanX, int spanY) {
+        for (int xi = x; xi < x + spanX; xi++) {
+            for (int yi = y; yi < y + spanY; yi++) {
+                if (mWidget[xi][yi] == CellType.IGNORE) continue;
+                if (mWidget[xi][yi] != CellType.EMPTY) return false;
+            }
+        }
+        return true;
+    }
+
     public void addWidget(int x, int y, int spanX, int spanY, char type) {
         Rect rect = new Rect(x, y + spanY - 1, x + spanX - 1, y);
         removeOverlappingItems(rect);
@@ -371,8 +384,8 @@
         s.append("\n");
         maxX = Math.min(maxX, mWidget.length);
         maxY = Math.min(maxY, mWidget[0].length);
-        for (int y = 0; y <= maxY; y++) {
-            for (int x = 0; x <= maxX; x++) {
+        for (int y = 0; y < maxY; y++) {
+            for (int x = 0; x < maxX; x++) {
                 s.append(mWidget[x][y]);
             }
             s.append('\n');
diff --git a/tests/src/com/android/launcher3/celllayout/board/CellType.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/CellType.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/CellType.java
diff --git a/tests/src/com/android/launcher3/celllayout/board/FolderPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/FolderPoint.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/FolderPoint.java
diff --git a/tests/src/com/android/launcher3/celllayout/board/IconPoint.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/IconPoint.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/IconPoint.java
diff --git a/tests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/IdenticalBoardComparator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/board/PermutedBoardComparator.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/PermutedBoardComparator.kt
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/PermutedBoardComparator.kt
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/PermutedBoardComparator.kt
diff --git a/tests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
similarity index 94%
rename from tests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
index 06a7db2..8a427dd 100644
--- a/tests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/TestWorkspaceBuilder.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
 
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Process;
@@ -32,11 +31,6 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.celllayout.board.CellLayoutBoard;
-import com.android.launcher3.celllayout.board.CellType;
-import com.android.launcher3.celllayout.board.FolderPoint;
-import com.android.launcher3.celllayout.board.IconPoint;
-import com.android.launcher3.celllayout.board.WidgetRect;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
@@ -56,12 +50,10 @@
     private UserHandle mMyUser;
 
     private Context mContext;
-    private ContentResolver mResolver;
 
     public TestWorkspaceBuilder(Context context) {
         mMyUser = Process.myUserHandle();
         mContext = context;
-        mResolver = mContext.getContentResolver();
     }
 
     /**
diff --git a/tests/src/com/android/launcher3/celllayout/board/WidgetRect.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/board/WidgetRect.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/board/WidgetRect.java
diff --git a/tests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java b/tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
rename to tests/multivalentTests/src/com/android/launcher3/icons/FastBitmapDrawableTest.java
diff --git a/tests/src/com/android/launcher3/logging/FileLogTest.java b/tests/multivalentTests/src/com/android/launcher3/logging/FileLogTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/logging/FileLogTest.java
rename to tests/multivalentTests/src/com/android/launcher3/logging/FileLogTest.java
diff --git a/tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt b/tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/logging/StartupLatencyLoggerTest.kt
diff --git a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
diff --git a/tests/src/com/android/launcher3/model/FactitiousDbController.kt b/tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/FactitiousDbController.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/FactitiousDbController.kt
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt
new file mode 100644
index 0000000..cfbde98
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.pm.PackageInstallInfo
+import com.android.launcher3.util.LauncherModelHelper
+import com.google.common.truth.Truth
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ItemInfoWithIconTest {
+
+    private var context = LauncherModelHelper.SandboxModelContext()
+    private lateinit var itemInfoWithIcon: ItemInfoWithIcon
+
+    @Before
+    fun setup() {
+        itemInfoWithIcon =
+            object : ItemInfoWithIcon() {
+                override fun clone(): ItemInfoWithIcon? {
+                    return null
+                }
+            }
+    }
+
+    @After
+    fun tearDown() {
+        context.destroy()
+    }
+
+    @Test
+    fun itemInfoWithIconDefaultParamsTest() {
+        Truth.assertThat(itemInfoWithIcon.isDisabled).isFalse()
+        Truth.assertThat(itemInfoWithIcon.isPendingDownload).isFalse()
+        Truth.assertThat(itemInfoWithIcon.isArchived).isFalse()
+    }
+
+    @Test
+    fun isDisabledOrPendingTest() {
+        itemInfoWithIcon.setProgressLevel(0, PackageInstallInfo.STATUS_INSTALLING)
+        Truth.assertThat(itemInfoWithIcon.isDisabled).isFalse()
+        Truth.assertThat(itemInfoWithIcon.isPendingDownload).isTrue()
+
+        itemInfoWithIcon.setProgressLevel(1, PackageInstallInfo.STATUS_INSTALLING)
+        Truth.assertThat(itemInfoWithIcon.isDisabled).isFalse()
+        Truth.assertThat(itemInfoWithIcon.isPendingDownload).isFalse()
+    }
+}
diff --git a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java b/tests/multivalentTests/src/com/android/launcher3/popup/PopupPopulatorTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/popup/PopupPopulatorTest.java
diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetDynamicColors.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetDynamicColors.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/AppWidgetDynamicColors.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetDynamicColors.java
diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetHidden.java
diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetNoConfig.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetNoConfig.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/AppWidgetNoConfig.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetNoConfig.java
diff --git a/tests/src/com/android/launcher3/testcomponent/AppWidgetWithConfig.java b/tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetWithConfig.java
similarity index 100%
rename from tests/src/com/android/launcher3/testcomponent/AppWidgetWithConfig.java
rename to tests/multivalentTests/src/com/android/launcher3/testcomponent/AppWidgetWithConfig.java
diff --git a/tests/src/com/android/launcher3/ui/TestViewHelpers.java b/tests/multivalentTests/src/com/android/launcher3/ui/TestViewHelpers.java
similarity index 100%
rename from tests/src/com/android/launcher3/ui/TestViewHelpers.java
rename to tests/multivalentTests/src/com/android/launcher3/ui/TestViewHelpers.java
diff --git a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java b/tests/multivalentTests/src/com/android/launcher3/util/ActivityContextWrapper.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/ActivityContextWrapper.java
rename to tests/multivalentTests/src/com/android/launcher3/util/ActivityContextWrapper.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/CancellableTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/CancellableTaskTest.kt
new file mode 100644
index 0000000..eb58096
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/CancellableTaskTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.rule.TestStabilityRule
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.locks.ReentrantLock
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit test for [CancellableTask] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CancellableTaskTest {
+
+    private lateinit var underTest: CancellableTask<Int>
+
+    private val lock = ReentrantLock()
+    private var result: Int = -1
+    private var isTaskExecuted = false
+    private var isCallbackExecuted = false
+
+    @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
+
+    @Before
+    fun setup() {
+        reset()
+        submitJob()
+    }
+
+    private fun submitJob() {
+        underTest =
+            CancellableTask(
+                {
+                    isTaskExecuted = true
+                    1
+                },
+                Executors.VIEW_PREINFLATION_EXECUTOR,
+                {
+                    isCallbackExecuted = true
+                    result = it + 1
+                }
+            )
+        Executors.UI_HELPER_EXECUTOR.execute(underTest)
+    }
+
+    @Test
+    fun run_and_complete() {
+        awaitAllExecutorCompleted()
+
+        assertTrue("task should be executed", isTaskExecuted)
+        assertTrue("callback should be executed", isCallbackExecuted)
+        assertEquals(2, result)
+    }
+
+    @Test
+    fun run_and_cancel_cancelTaskAndCallback() {
+        awaitAllExecutorCompleted()
+        reset()
+        lock.lock()
+        Executors.UI_HELPER_EXECUTOR.submit { lock.lock() }
+        submitJob()
+
+        underTest.cancel()
+
+        lock.unlock() // unblock task on UI_HELPER_EXECUTOR
+        awaitAllExecutorCompleted()
+        assertFalse("task should not be executed.", isTaskExecuted)
+        assertFalse("callback should not be executed.", isCallbackExecuted)
+        assertEquals(0, result)
+    }
+
+    @Test
+    fun run_and_cancel_cancelCallback() {
+        awaitAllExecutorCompleted()
+        reset()
+        lock.lock()
+        Executors.VIEW_PREINFLATION_EXECUTOR.submit { lock.lock() }
+        submitJob()
+        awaitExecutorCompleted(Executors.UI_HELPER_EXECUTOR)
+        assertTrue("task should be executed.", isTaskExecuted)
+
+        underTest.cancel()
+
+        lock.unlock() // unblock callback on VIEW_PREINFLATION_EXECUTOR
+        awaitExecutorCompleted(Executors.VIEW_PREINFLATION_EXECUTOR)
+        assertFalse("callback should not be executed.", isCallbackExecuted)
+        assertEquals(0, result)
+    }
+
+    @Test
+    fun run_and_cancelAfterCompletion_executeAll() {
+        awaitAllExecutorCompleted()
+
+        underTest.cancel()
+
+        assertTrue("task should be executed", isTaskExecuted)
+        assertTrue("callback should be executed", isCallbackExecuted)
+        assertEquals(2, result)
+    }
+
+    private fun awaitExecutorCompleted(executor: ExecutorService) {
+        executor.submit<Any> { null }.get()
+    }
+
+    private fun awaitAllExecutorCompleted() {
+        awaitExecutorCompleted(Executors.UI_HELPER_EXECUTOR)
+        awaitExecutorCompleted(Executors.VIEW_PREINFLATION_EXECUTOR)
+    }
+
+    private fun reset() {
+        result = 0
+        isTaskExecuted = false
+        isCallbackExecuted = false
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/GridOccupancyTest.java b/tests/multivalentTests/src/com/android/launcher3/util/GridOccupancyTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/GridOccupancyTest.java
rename to tests/multivalentTests/src/com/android/launcher3/util/GridOccupancyTest.java
diff --git a/tests/src/com/android/launcher3/util/IconSizeStepsTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/IconSizeStepsTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/util/IconSizeStepsTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/IconSizeStepsTest.kt
diff --git a/tests/src/com/android/launcher3/util/IntArrayTest.java b/tests/multivalentTests/src/com/android/launcher3/util/IntArrayTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/IntArrayTest.java
rename to tests/multivalentTests/src/com/android/launcher3/util/IntArrayTest.java
diff --git a/tests/src/com/android/launcher3/util/IntSetTest.java b/tests/multivalentTests/src/com/android/launcher3/util/IntSetTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/IntSetTest.java
rename to tests/multivalentTests/src/com/android/launcher3/util/IntSetTest.java
diff --git a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
rename to tests/multivalentTests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
similarity index 91%
rename from tests/src/com/android/launcher3/util/LauncherModelHelper.java
rename to tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 244dc26..002f496 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -52,18 +52,11 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.testing.TestInformationProvider;
-import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.window.WindowManagerProxy;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -233,14 +226,8 @@
         private final PackageManager mPm;
         private final File mDbDir;
 
-        SandboxModelContext() {
-            super(ApplicationProvider.getApplicationContext(),
-                    UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
-                    LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
-                    DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
-                    SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
-                    LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
-                    ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
+        public SandboxModelContext() {
+            super(ApplicationProvider.getApplicationContext());
 
             // System settings cache content provider. Ensure that they are statically initialized
             Settings.Secure.getString(
@@ -255,18 +242,13 @@
         }
 
         @Override
-        protected <T> T createObject(MainThreadInitializedObject<T> object) {
+        public <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
             if (object == LauncherAppState.INSTANCE) {
                 return (T) new LauncherAppState(this, null /* iconCacheFileName */);
             }
             return super.createObject(object);
         }
 
-        public SandboxModelContext allow(MainThreadInitializedObject object) {
-            mAllowedObjects.add(object);
-            return this;
-        }
-
         @Override
         public File getDatabasePath(String name) {
             if (!mDbDir.exists()) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
new file mode 100644
index 0000000..6bd182b
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -0,0 +1,101 @@
+package com.android.launcher3.util
+
+import android.content.ContentValues
+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
+import com.android.launcher3.LauncherSettings.Favorites.CELLX
+import com.android.launcher3.LauncherSettings.Favorites.CELLY
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.INTENT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID
+import com.android.launcher3.LauncherSettings.Favorites.RESTORED
+import com.android.launcher3.LauncherSettings.Favorites.SCREEN
+import com.android.launcher3.LauncherSettings.Favorites.SPANX
+import com.android.launcher3.LauncherSettings.Favorites.SPANY
+import com.android.launcher3.LauncherSettings.Favorites.TITLE
+import com.android.launcher3.LauncherSettings.Favorites._ID
+import com.android.launcher3.model.BgDataModel
+import com.android.launcher3.model.ModelDbController
+
+object ModelTestExtensions {
+    /** Clears and reloads Launcher db to cleanup the workspace */
+    fun LauncherModel.clearModelDb() {
+        // Load the model once so that there is no pending migration:
+        loadModelSync()
+        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
+            modelDbController.run {
+                tryMigrateDB(null /* restoreEventLogger */)
+                createEmptyDB()
+                clearEmptyDbFlag()
+            }
+        }
+        // Reload model
+        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { forceReload() }
+        loadModelSync()
+    }
+
+    /** Loads the model in memory synchronously */
+    fun LauncherModel.loadModelSync() {
+        val mockCb: BgDataModel.Callbacks = object : BgDataModel.Callbacks {}
+        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { addCallbacksAndLoad(mockCb) }
+        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {}
+        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) {}
+        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { removeCallbacks(mockCb) }
+    }
+
+    /** Adds and commits a new item to Launcher.db */
+    fun LauncherModel.addItem(
+        title: String = "LauncherTestApp",
+        intent: String =
+            "#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;component=com.google.android.apps.nexuslauncher.tests/com.android.launcher3.testcomponent.BaseTestingActivity;launchFlags=0x10200000;end",
+        type: Int = ITEM_TYPE_APPLICATION,
+        restoreFlags: Int = 0,
+        screen: Int = 0,
+        container: Int = CONTAINER_DESKTOP,
+        x: Int,
+        y: Int,
+        spanX: Int = 1,
+        spanY: Int = 1,
+        id: Int = 0,
+        profileId: Int = 0,
+        tableName: String = Favorites.TABLE_NAME,
+        appWidgetId: Int = -1,
+        appWidgetSource: Int = -1,
+        appWidgetProvider: String? = null
+    ) {
+        loadModelSync()
+        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
+            val controller: ModelDbController = modelDbController
+            controller.tryMigrateDB(null /* restoreEventLogger */)
+            modelDbController.newTransaction().use { transaction ->
+                val values =
+                    ContentValues().apply {
+                        values[_ID] = id
+                        values[TITLE] = title
+                        values[PROFILE_ID] = profileId
+                        values[CONTAINER] = container
+                        values[SCREEN] = screen
+                        values[CELLX] = x
+                        values[CELLY] = y
+                        values[SPANX] = spanX
+                        values[SPANY] = spanY
+                        values[ITEM_TYPE] = type
+                        values[RESTORED] = restoreFlags
+                        values[INTENT] = intent
+                        values[APPWIDGET_ID] = appWidgetId
+                        values[APPWIDGET_SOURCE] = appWidgetSource
+                        values[APPWIDGET_PROVIDER] = appWidgetProvider
+                    }
+                // Migrate any previous data so that the DB state is correct
+                controller.insert(tableName, values)
+                transaction.commit()
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
diff --git a/tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/MultiScalePropertyTest.kt
diff --git a/tests/src/com/android/launcher3/util/PackageUserKeyTest.java b/tests/multivalentTests/src/com/android/launcher3/util/PackageUserKeyTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/PackageUserKeyTest.java
rename to tests/multivalentTests/src/com/android/launcher3/util/PackageUserKeyTest.java
diff --git a/tests/src/com/android/launcher3/util/ReflectionHelpers.java b/tests/multivalentTests/src/com/android/launcher3/util/ReflectionHelpers.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/ReflectionHelpers.java
rename to tests/multivalentTests/src/com/android/launcher3/util/ReflectionHelpers.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
new file mode 100644
index 0000000..3f37563
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+
+import android.content.ContextWrapper;
+
+import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.AllAppsStore;
+import com.android.launcher3.allapps.AlphabeticalAppsList;
+import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.popup.PopupDataProvider;
+
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * {@link ContextWrapper} around {@link ActivityContextWrapper} with internal Launcher interface for
+ * testing.
+ *
+ * There are 2 constructors in this class. The base context can be {@link SandboxContext} or
+ * Instrumentation target context.
+ * Using {@link SandboxContext} as base context allows custom implementations for
+ * MainThreadInitializedObject providers.
+ */
+
+public class TestSandboxModelContextWrapper extends ActivityContextWrapper implements
+        BgDataModel.Callbacks {
+
+    protected AllAppsStore<ActivityContextWrapper> mAllAppsStore;
+    protected AlphabeticalAppsList<ActivityContextWrapper> mAppsList;
+
+    public final CountDownLatch mBindCompleted = new CountDownLatch(1);
+
+    protected ActivityAllAppsContainerView<ActivityContextWrapper> mAppsView;
+
+    private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
+    protected final UserCache mUserCache;
+
+    public TestSandboxModelContextWrapper(SandboxContext base) {
+        super(base);
+        mUserCache = base.getObject(UserCache.INSTANCE);
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
+                mAppsView = new ActivityAllAppsContainerView<>(this));
+        mAppsList = mAppsView.getPersonalAppList();
+        mAllAppsStore = mAppsView.getAppsStore();
+    }
+
+    public TestSandboxModelContextWrapper() {
+        super(getInstrumentation().getTargetContext());
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() ->
+                mAppsView = new ActivityAllAppsContainerView<>(this));
+        mUserCache = UserCache.getInstance(this);
+        mAppsList = mAppsView.getPersonalAppList();
+        mAllAppsStore = mAppsView.getAppsStore();
+    }
+    @Nullable
+    @Override
+    public PopupDataProvider getPopupDataProvider() {
+        return mPopupDataProvider;
+    }
+
+    @Override
+    public ActivityAllAppsContainerView<ActivityContextWrapper> getAppsView() {
+        return mAppsView;
+    }
+
+    @Override
+    public void bindAllApplications(AppInfo[] apps, int flags,
+            Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
+        mAllAppsStore.setApps(apps, flags, packageUserKeytoUidMap);
+        mBindCompleted.countDown();
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
similarity index 81%
rename from tests/src/com/android/launcher3/util/TestUtil.java
rename to tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
index 683f323..3646f0c 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
@@ -46,12 +46,8 @@
 
 import androidx.test.uiautomator.UiDevice;
 
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.config.FeatureFlags.BooleanFlag;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.Assert;
 
@@ -66,8 +62,6 @@
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.function.Predicate;
-import java.util.function.ToIntFunction;
 
 public class TestUtil {
     private static final String TAG = "TestUtil";
@@ -103,7 +97,9 @@
             out.close();
 
             final String result = UiDevice.getInstance(instrumentation)
-                    .executeShellCommand("pm install --user " + userId + " " + apkFilename);
+                    .executeShellCommand(String.format("pm install -i %s --user ",
+                            instrumentation.getContext().getPackageName())
+                            + userId + " " + apkFilename);
             Assert.assertTrue(
                     "Failed to install wellbeing test apk; make sure the device is rooted",
                     "Success".equals(result.replaceAll("\\s+", "")));
@@ -136,49 +132,12 @@
      */
     public static Point[] getCornersAndCenterPositions(LauncherInstrumentation launcher) {
         final Point dimensions = launcher.getWorkspace().getIconGridDimensions();
-        if (TestStabilityRule.isPresubmit()) {
-            // Return only center in presubmit to fit under the presubmit SLO.
-            return new Point[]{
-                    new Point(dimensions.x / 2, dimensions.y / 2)
-            };
-        } else {
-            return new Point[]{
-                    new Point(0, 1),
-                    new Point(0, dimensions.y - 2),
-                    new Point(dimensions.x - 1, 1),
-                    new Point(dimensions.x - 1, dimensions.y - 2),
-                    new Point(dimensions.x / 2, dimensions.y / 2)
-            };
-        }
-    }
-
-    /**
-     * Utility class to override a boolean flag during test. Note that the returned SafeCloseable
-     * must be closed to restore the original state
-     */
-    public static SafeCloseable overrideFlag(BooleanFlag flag, boolean value) {
-        Predicate<BooleanFlag> originalProxy = FeatureFlags.sBooleanReader;
-        Predicate<BooleanFlag> testProxy = f -> f == flag ? value : originalProxy.test(f);
-        FeatureFlags.sBooleanReader = testProxy;
-        return () -> {
-            if (FeatureFlags.sBooleanReader == testProxy) {
-                FeatureFlags.sBooleanReader = originalProxy;
-            }
-        };
-    }
-
-    /**
-     * Utility class to override a int flag during test. Note that the returned SafeCloseable
-     * must be closed to restore the original state
-     */
-    public static SafeCloseable overrideFlag(IntFlag flag, int value) {
-        ToIntFunction<IntFlag> originalProxy = FeatureFlags.sIntReader;
-        ToIntFunction<IntFlag> testProxy = f -> f == flag ? value : originalProxy.applyAsInt(f);
-        FeatureFlags.sIntReader = testProxy;
-        return () -> {
-            if (FeatureFlags.sIntReader == testProxy) {
-                FeatureFlags.sIntReader = originalProxy;
-            }
+        return new Point[]{
+                new Point(0, 1),
+                new Point(0, dimensions.y - 2),
+                new Point(dimensions.x - 1, 1),
+                new Point(dimensions.x - 1, dimensions.y - 2),
+                new Point(dimensions.x / 2, dimensions.y / 2)
         };
     }
 
diff --git a/tests/src/com/android/launcher3/util/TouchUtilTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/TouchUtilTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/util/TouchUtilTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/TouchUtilTest.kt
diff --git a/tests/src/com/android/launcher3/util/WidgetUtils.java b/tests/multivalentTests/src/com/android/launcher3/util/WidgetUtils.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/WidgetUtils.java
rename to tests/multivalentTests/src/com/android/launcher3/util/WidgetUtils.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
new file mode 100644
index 0000000..da96939
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherPrefs
+import java.io.File
+import java.nio.file.Paths
+import kotlin.io.path.pathString
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Removes all launcher's DBs from the device and copies the dbs in
+ * assets/databases/BackupAndRestore to the device. It also set's the needed LauncherPrefs variables
+ * needed to kickstart a backup and restore.
+ */
+class BackAndRestoreRule : TestRule {
+
+    private val phoneContext = getInstrumentation().targetContext
+
+    private fun dbBackUp() = File(phoneContext.dataDir.path, "/databasesBackUp")
+
+    private fun dbDirectory() = File(phoneContext.dataDir.path, "/databases")
+
+    private fun isWorkspaceDatabase(rawFileName: String): Boolean {
+        val fileName = Paths.get(rawFileName).fileName.pathString
+        return fileName.startsWith("launcher") && fileName.endsWith(".db")
+    }
+
+    fun getDatabaseFiles() = dbDirectory().listFiles().filter { isWorkspaceDatabase(it.name) }
+
+    /**
+     * Setting RESTORE_DEVICE would trigger a restore next time the Launcher starts, and we remove
+     * the widgets and apps ids to prevent issues when loading the database.
+     */
+    private fun setRestoreConstants() {
+        LauncherPrefs.get(phoneContext)
+            .put(LauncherPrefs.RESTORE_DEVICE.to(InvariantDeviceProfile.TYPE_MULTI_DISPLAY))
+        LauncherPrefs.get(phoneContext)
+            .remove(LauncherPrefs.OLD_APP_WIDGET_IDS, LauncherPrefs.APP_WIDGET_IDS)
+    }
+
+    private fun uploadDatabase(dbName: String) {
+        val file = File(File(getInstrumentation().targetContext.dataDir, "/databases"), dbName)
+        file.writeBytes(
+            getInstrumentation()
+                .context
+                .assets
+                .open("databases/BackupAndRestore/$dbName")
+                .readBytes()
+        )
+        file.setWritable(true, false)
+    }
+
+    private fun uploadDbs() {
+        uploadDatabase("launcher.db")
+        uploadDatabase("launcher_4_by_4.db")
+        uploadDatabase("launcher_4_by_5.db")
+        uploadDatabase("launcher_3_by_3.db")
+    }
+
+    private fun savePreviousState() {
+        dbBackUp().deleteRecursively()
+        if (!dbDirectory().renameTo(dbBackUp())) {
+            throw Exception("Unable to move databases to backup directory")
+        }
+        dbDirectory().mkdir()
+        if (!dbDirectory().exists()) {
+            throw Exception("Databases directory doesn't exists")
+        }
+    }
+
+    private fun restorePreviousState() {
+        dbDirectory().deleteRecursively()
+        if (!dbBackUp().renameTo(dbDirectory())) {
+            throw Exception("Unable to restore backup directory to databases directory")
+        }
+        dbBackUp().delete()
+    }
+
+    fun before() {
+        savePreviousState()
+        setRestoreConstants()
+        uploadDbs()
+    }
+
+    fun after() {
+        restorePreviousState()
+    }
+
+    override fun apply(base: Statement?, description: Description?): Statement =
+        object : Statement() {
+            override fun evaluate() {
+                before()
+                try {
+                    base?.evaluate()
+                } finally {
+                    after()
+                }
+            }
+        }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
similarity index 96%
rename from tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
rename to tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index b51045f..909aabd 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -83,6 +83,7 @@
 
     public static int getRunFlavor() {
         if (sRunFlavor != 0) return sRunFlavor;
+        if (isRobolectricTest()) return PLATFORM_POSTSUBMIT;
 
         final String flavorOverride = InstrumentationRegistry.getArguments().getString("flavor");
 
@@ -150,4 +151,8 @@
     public static boolean isPresubmit() {
         return getRunFlavor() == PLATFORM_PRESUBMIT;
     }
+
+    public static boolean isRobolectricTest() {
+        return Build.FINGERPRINT.contains("robolectric");
+    }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt
new file mode 100644
index 0000000..4819388
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.window
+
+import android.graphics.Rect
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.window.WindowManagerProxy.areBottomDisplayCutoutsSmallAndAtCorners
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Unit test for [WindowManagerProxy] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WindowManagerProxyTest {
+
+    private val windowWidthPx = 2000
+
+    private val bottomLeftCutout = Rect(0, 2364, 136, 2500)
+    private val bottomRightCutout = Rect(1864, 2364, 2000, 2500)
+
+    private val bottomLeftCutoutWithOffset = Rect(10, 2364, 136, 2500)
+    private val bottomRightCutoutWithOffset = Rect(1864, 2364, 1990, 2500)
+
+    private val maxWidthAndHeightOfSmallCutoutPx = 136
+
+    @Test
+    fun cutout_at_bottom_right_corner() {
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bottomRightCutout,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_at_bottom_left_corner_with_offset() {
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bottomLeftCutoutWithOffset,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_at_bottom_right_corner_with_offset() {
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bottomRightCutoutWithOffset,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_at_bottom_left_corner() {
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bottomLeftCutout,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_at_bottom_edge_at_bottom_corners() {
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bottomLeftCutout,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_too_big_not_at_bottom_corners() {
+        // Rect in size of 200px
+        val bigBottomLeftCutout = Rect(0, 2300, 200, 2500)
+
+        assertFalse(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                bigBottomLeftCutout,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_too_small_at_bottom_corners() {
+        // Rect in size of 100px
+        val smallBottomLeft = Rect(0, 2400, 100, 2500)
+
+        assertTrue(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                smallBottomLeft,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+
+    @Test
+    fun cutout_empty_not_at_bottom_corners() {
+        val emptyRect = Rect(0, 0, 0, 0)
+
+        assertFalse(
+            areBottomDisplayCutoutsSmallAndAtCorners(
+                emptyRect,
+                windowWidthPx,
+                maxWidthAndHeightOfSmallCutoutPx
+            )
+        )
+    }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/OWNERS b/tests/multivalentTests/src/com/android/launcher3/widget/picker/OWNERS
new file mode 100644
index 0000000..775b0c7
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/OWNERS
@@ -0,0 +1,18 @@
+set noparent
+
+# Bug component: 1481801
+# People who can approve changes for submission
+#
+
+# Widget Picker OWNERS
+zakcohen@google.com
+shamalip@google.com
+wvk@google.com
+
+# For Tests
+vadimt@google.com
+
+# Launcher OWNERS
+captaincole@google.com
+sunnygoyal@google.com
+
diff --git a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/tests/multivalentTests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
rename to tests/multivalentTests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
index 583d37f..8457ac6 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
@@ -78,7 +78,7 @@
     public void afterTextChanged_shouldInformSearchModeListenerToEnterSearch() {
         mEditText.setText("abc");
 
-        verify(mSearchModeListener).enterSearchMode();
+        verify(mSearchModeListener).enterSearchMode(true);
         verifyNoMoreInteractions(mSearchModeListener);
     }
 
diff --git a/tests/multivalentTestsForDevice b/tests/multivalentTestsForDevice
new file mode 120000
index 0000000..20ee34a
--- /dev/null
+++ b/tests/multivalentTestsForDevice
@@ -0,0 +1 @@
+multivalentTests
\ No newline at end of file
diff --git a/tests/multivalentTestsForDeviceless b/tests/multivalentTestsForDeviceless
new file mode 120000
index 0000000..20ee34a
--- /dev/null
+++ b/tests/multivalentTestsForDeviceless
@@ -0,0 +1 @@
+multivalentTests
\ No newline at end of file
diff --git a/tests/res/layout/test_layout_appwidget_red.xml b/tests/res/layout/test_layout_appwidget_red.xml
index 48d3e81..0f2bda3 100644
--- a/tests/res/layout/test_layout_appwidget_red.xml
+++ b/tests/res/layout/test_layout_appwidget_red.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/content"
     android:orientation="vertical"
     android:background="#FFFF0000"
     android:layout_width="match_parent"
diff --git a/tests/res/values/styles.xml b/tests/res/values/styles.xml
new file mode 100644
index 0000000..1e1a2cd
--- /dev/null
+++ b/tests/res/values/styles.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="Theme.TestActivities" parent="@android:style/Theme.DeviceDefault.DayNight">
+        <!-- Hardcoded ActionBar height to avoid changes while emulating -->
+        <!-- (56dp - default for handheld) -->
+        <item name="android:actionBarSize">168px</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tests/res/xml/invalid_responsive_spec_1.xml b/tests/res/xml/invalid_responsive_spec_1.xml
index d1bcf65..7845d1e 100644
--- a/tests/res/xml/invalid_responsive_spec_1.xml
+++ b/tests/res/xml/invalid_responsive_spec_1.xml
@@ -27,7 +27,7 @@
     <workspaceSpec
         launcher:maxAvailableSize="9999dp"
         launcher:dimensionType="width">
-        <cellSize launcher:ofRemainderSpace="0.25" />
+        <cellSize launcher:ofRemainderSpace="1" />
         <endPadding launcher:fixedSize="22dp" />
         <gutter launcher:fixedSize="16dp" />
         <startPadding launcher:fixedSize="22dp" />
diff --git a/tests/res/xml/invalid_responsive_spec_2.xml b/tests/res/xml/invalid_responsive_spec_2.xml
index 49e1f93..ae30bb9 100644
--- a/tests/res/xml/invalid_responsive_spec_2.xml
+++ b/tests/res/xml/invalid_responsive_spec_2.xml
@@ -28,7 +28,7 @@
         <workspaceSpec
             launcher:maxAvailableSize="9999dp"
             launcher:dimensionType="width">
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
             <endPadding launcher:fixedSize="22dp" />
             <gutter launcher:fixedSize="16dp" />
             <startPadding launcher:fixedSize="22dp" />
@@ -38,7 +38,7 @@
     <workspaceSpec
         launcher:maxAvailableSize="9999dp"
         launcher:dimensionType="width">
-        <cellSize launcher:ofRemainderSpace="0.25" />
+        <cellSize launcher:ofRemainderSpace="1" />
         <endPadding launcher:fixedSize="22dp" />
         <gutter launcher:fixedSize="16dp" />
         <startPadding launcher:fixedSize="22dp" />
diff --git a/tests/res/xml/valid_responsive_spec_unsorted.xml b/tests/res/xml/valid_responsive_spec_unsorted.xml
index 9a463d5..8676f48 100644
--- a/tests/res/xml/valid_responsive_spec_unsorted.xml
+++ b/tests/res/xml/valid_responsive_spec_unsorted.xml
@@ -22,7 +22,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="34dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
 
         <!-- Height spec -->
@@ -32,7 +32,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="24dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
 
         <!-- Width spec -->
@@ -42,7 +42,7 @@
             <startPadding launcher:fixedSize="16dp" />
             <endPadding launcher:fixedSize="64dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
         <workspaceSpec
             launcher:dimensionType="width"
@@ -50,7 +50,7 @@
             <startPadding launcher:fixedSize="36dp" />
             <endPadding launcher:fixedSize="80dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
         <workspaceSpec
             launcher:dimensionType="width"
@@ -58,7 +58,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="36dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 
@@ -71,7 +71,7 @@
             <startPadding launcher:fixedSize="2dp" />
             <endPadding launcher:fixedSize="2dp" />
             <gutter launcher:fixedSize="8dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
 
         <!-- Width spec -->
@@ -81,7 +81,7 @@
             <startPadding launcher:fixedSize="1dp" />
             <endPadding launcher:fixedSize="1dp" />
             <gutter launcher:fixedSize="8dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 
@@ -122,7 +122,7 @@
             <startPadding launcher:fixedSize="22dp" />
             <endPadding launcher:fixedSize="22dp" />
             <gutter launcher:fixedSize="16dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_file.xml b/tests/res/xml/valid_workspace_file.xml
index 9c44502..dc9963a 100644
--- a/tests/res/xml/valid_workspace_file.xml
+++ b/tests/res/xml/valid_workspace_file.xml
@@ -54,7 +54,7 @@
             <startPadding launcher:fixedSize="22dp" />
             <endPadding launcher:fixedSize="22dp" />
             <gutter launcher:fixedSize="16dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 
@@ -67,7 +67,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="24dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
         <workspaceSpec
             launcher:dimensionType="height"
@@ -75,7 +75,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="34dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
 
         <!-- Width spec -->
@@ -85,7 +85,7 @@
             <startPadding launcher:fixedSize="0dp" />
             <endPadding launcher:fixedSize="36dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
         <workspaceSpec
             launcher:dimensionType="width"
@@ -93,7 +93,7 @@
             <startPadding launcher:fixedSize="16dp" />
             <endPadding launcher:fixedSize="64dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
         <workspaceSpec
             launcher:dimensionType="width"
@@ -101,7 +101,7 @@
             <startPadding launcher:fixedSize="36dp" />
             <endPadding launcher:fixedSize="80dp" />
             <gutter launcher:fixedSize="12dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 </workspaceSpecs>
diff --git a/tests/res/xml/valid_workspace_unsorted_file.xml b/tests/res/xml/valid_workspace_unsorted_file.xml
index 6bf7c78..f783e9f 100644
--- a/tests/res/xml/valid_workspace_unsorted_file.xml
+++ b/tests/res/xml/valid_workspace_unsorted_file.xml
@@ -52,7 +52,7 @@
             <startPadding launcher:fixedSize="22dp" />
             <endPadding launcher:fixedSize="22dp" />
             <gutter launcher:fixedSize="16dp" />
-            <cellSize launcher:ofRemainderSpace="0.25" />
+            <cellSize launcher:ofRemainderSpace="1" />
         </workspaceSpec>
     </specs>
 </workspaceSpecs>
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index e46726d..aefc2db 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -19,17 +19,25 @@
 import android.content.res.Configuration
 import android.graphics.Point
 import android.graphics.Rect
+import android.platform.test.flag.junit.SetFlagsRule
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.IgnoreLimit
+import android.platform.test.rule.LimitDevicesRule
 import android.util.DisplayMetrics
 import android.view.Surface
 import androidx.test.core.app.ApplicationProvider
+import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.testing.shared.ResourceUtils
 import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext
 import com.android.launcher3.util.NavigationMode
 import com.android.launcher3.util.WindowBounds
 import com.android.launcher3.util.rule.TestStabilityRule
+import com.android.launcher3.util.rule.setFlags
 import com.android.launcher3.util.window.CachedDisplayInfo
 import com.android.launcher3.util.window.WindowManagerProxy
+import com.google.common.truth.Truth
 import java.io.BufferedReader
 import java.io.File
 import java.io.PrintWriter
@@ -38,6 +46,7 @@
 import kotlin.math.min
 import org.junit.Rule
 import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.whenever
@@ -48,15 +57,22 @@
  *
  * For an implementation that mocks InvariantDeviceProfile, use [FakeInvariantDeviceProfileTest]
  */
+@AllowedDevices(allowed = [DeviceProduct.CF_PHONE])
+@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
 abstract class AbstractDeviceProfileTest {
+    protected val testContext: Context = InstrumentationRegistry.getInstrumentation().context
     protected lateinit var context: SandboxContext
     protected open val runningContext: Context = ApplicationProvider.getApplicationContext()
     private val displayController: DisplayController = mock()
     private val windowManagerProxy: WindowManagerProxy = mock()
     private val launcherPrefs: LauncherPrefs = mock()
 
+    @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
     @Rule @JvmField val testStabilityRule = TestStabilityRule()
 
+    @Rule @JvmField val limitDevicesRule = LimitDevicesRule()
+
     class DeviceSpec(
         val naturalSize: Pair<Int, Int>,
         var densityDpi: Int,
@@ -113,8 +129,7 @@
     ) {
         val (naturalX, naturalY) = deviceSpec.naturalSize
         val windowsBounds = phoneWindowsBounds(deviceSpec, isGestureMode, naturalX, naturalY)
-        val displayInfo =
-            CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
+        val displayInfo = CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0)
         val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
 
         initializeCommonVars(
@@ -133,8 +148,7 @@
     ) {
         val (naturalX, naturalY) = deviceSpec.naturalSize
         val windowsBounds = tabletWindowsBounds(deviceSpec, naturalX, naturalY)
-        val displayInfo =
-            CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0, Rect(0, 0, 0, 0))
+        val displayInfo = CachedDisplayInfo(Point(naturalX, naturalY), Surface.ROTATION_0)
         val perDisplayBoundsCache = mapOf(displayInfo to windowsBounds)
 
         initializeCommonVars(
@@ -157,21 +171,13 @@
         val unfoldedWindowsBounds =
             tabletWindowsBounds(deviceSpecUnfolded, unfoldedNaturalX, unfoldedNaturalY)
         val unfoldedDisplayInfo =
-            CachedDisplayInfo(
-                Point(unfoldedNaturalX, unfoldedNaturalY),
-                Surface.ROTATION_0,
-                Rect(0, 0, 0, 0)
-            )
+            CachedDisplayInfo(Point(unfoldedNaturalX, unfoldedNaturalY), Surface.ROTATION_0)
 
         val (foldedNaturalX, foldedNaturalY) = deviceSpecFolded.naturalSize
         val foldedWindowsBounds =
             phoneWindowsBounds(deviceSpecFolded, isGestureMode, foldedNaturalX, foldedNaturalY)
         val foldedDisplayInfo =
-            CachedDisplayInfo(
-                Point(foldedNaturalX, foldedNaturalY),
-                Surface.ROTATION_0,
-                Rect(0, 0, 0, 0)
-            )
+            CachedDisplayInfo(Point(foldedNaturalX, foldedNaturalY), Surface.ROTATION_0)
 
         val perDisplayBoundsCache =
             mapOf(
@@ -269,6 +275,8 @@
         isGestureMode: Boolean = true,
         densityDpi: Int
     ) {
+        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_TWOLINE_TOGGLE)
+        LauncherPrefs.get(testContext).put(LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE, true)
         val windowsBounds = perDisplayBoundsCache[displayInfo]!!
         val realBounds = windowsBounds[rotation]
         whenever(windowManagerProxy.getDisplayInfo(any())).thenReturn(displayInfo)
@@ -279,6 +287,9 @@
             .thenReturn(
                 if (isGestureMode) NavigationMode.NO_BUTTON else NavigationMode.THREE_BUTTONS
             )
+        doReturn(WindowManagerProxy.INSTANCE[runningContext].isTaskbarDrawnInProcess)
+            .whenever(windowManagerProxy)
+            .isTaskbarDrawnInProcess()
 
         val density = densityDpi / DisplayMetrics.DENSITY_DEFAULT.toFloat()
         val config =
@@ -289,13 +300,7 @@
                 smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
             }
         val configurationContext = runningContext.createConfigurationContext(config)
-        context =
-            SandboxContext(
-                configurationContext,
-                DisplayController.INSTANCE,
-                WindowManagerProxy.INSTANCE,
-                LauncherPrefs.INSTANCE
-            )
+        context = SandboxContext(configurationContext)
         context.putObject(DisplayController.INSTANCE, displayController)
         context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
         context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
@@ -306,6 +311,13 @@
         whenever(info.isTransientTaskbar).thenReturn(isGestureMode)
     }
 
+    /** Asserts that the given device profile matches a previously dumped device profile state. */
+    protected fun assertDump(dp: DeviceProfile, folderName: String, filename: String) {
+        val dump = dump(context!!, dp, "${folderName}_$filename.txt")
+        var expected = readDumpFromAssets(testContext, "$folderName/$filename.txt")
+        Truth.assertThat(dump).isEqualTo(expected)
+    }
+
     /** Create a new dump of DeviceProfile, saves to a file in the device and returns it */
     protected fun dump(context: Context, dp: DeviceProfile, fileName: String): String {
         val stringWriter = StringWriter()
diff --git a/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt b/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
new file mode 100644
index 0000000..7ff544d
--- /dev/null
+++ b/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3
+
+import android.view.View
+import com.android.launcher3.dragndrop.DragLayer
+import com.android.launcher3.views.ActivityContext
+import org.junit.Before
+import org.junit.Test
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.whenever
+
+/** Test for AbstractFloatingViewHelper */
+class AbstractFloatingViewHelperTest {
+    private val activityContext: ActivityContext = mock()
+    private val dragLayer: DragLayer = mock()
+    private val view: View = mock()
+    private val folderView: AbstractFloatingView = mock()
+    private val taskMenuView: AbstractFloatingView = mock()
+    private val abstractFloatingViewHelper = AbstractFloatingViewHelper()
+
+    @Before
+    fun setup() {
+        whenever(activityContext.dragLayer).thenReturn(dragLayer)
+        whenever(dragLayer.childCount).thenReturn(3)
+        whenever(dragLayer.getChildAt(0)).thenReturn(view)
+        whenever(dragLayer.getChildAt(1)).thenReturn(folderView)
+        whenever(dragLayer.getChildAt(2)).thenReturn(taskMenuView)
+        whenever(folderView.isOfType(any())).thenAnswer {
+            (it.getArgument<Int>(0) and AbstractFloatingView.TYPE_FOLDER) != 0
+        }
+        whenever(taskMenuView.isOfType(any())).thenAnswer {
+            (it.getArgument<Int>(0) and AbstractFloatingView.TYPE_TASK_MENU) != 0
+        }
+    }
+
+    @Test
+    fun closeOpenViews_all() {
+        abstractFloatingViewHelper.closeOpenViews(
+            activityContext,
+            true,
+            AbstractFloatingView.TYPE_ALL
+        )
+
+        verifyZeroInteractions(view)
+        verify(folderView).close(true)
+        verify(taskMenuView).close(true)
+    }
+
+    @Test
+    fun closeOpenViews_taskMenu() {
+        abstractFloatingViewHelper.closeOpenViews(
+            activityContext,
+            true,
+            AbstractFloatingView.TYPE_TASK_MENU
+        )
+
+        verifyZeroInteractions(view)
+        verify(folderView, never()).close(any())
+        verify(taskMenuView).close(true)
+    }
+
+    @Test
+    fun closeOpenViews_other() {
+        abstractFloatingViewHelper.closeOpenViews(
+            activityContext,
+            true,
+            AbstractFloatingView.TYPE_PIN_IME_POPUP
+        )
+
+        verifyZeroInteractions(view)
+        verify(folderView, never()).close(any())
+        verify(taskMenuView, never()).close(any())
+    }
+
+    @Test
+    fun closeOpenViews_both_animationOff() {
+        abstractFloatingViewHelper.closeOpenViews(
+            activityContext,
+            false,
+            AbstractFloatingView.TYPE_FOLDER or AbstractFloatingView.TYPE_TASK_MENU
+        )
+
+        verifyZeroInteractions(view)
+        verify(folderView).close(false)
+        verify(taskMenuView).close(false)
+    }
+}
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index 30b5663..13d7499 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -18,6 +18,10 @@
 import android.content.Context
 import android.graphics.PointF
 import android.graphics.Rect
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.IgnoreLimit
+import android.platform.test.rule.LimitDevicesRule
 import android.util.SparseArray
 import androidx.test.core.app.ApplicationProvider
 import com.android.launcher3.DeviceProfile.DEFAULT_DIMENSION_PROVIDER
@@ -27,6 +31,7 @@
 import java.io.PrintWriter
 import java.io.StringWriter
 import org.junit.Before
+import org.junit.Rule
 import org.mockito.kotlin.any
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.whenever
@@ -37,6 +42,8 @@
  *
  * For an implementation that creates InvariantDeviceProfile, use [AbstractDeviceProfileTest]
  */
+@AllowedDevices(allowed = [DeviceProduct.CF_PHONE])
+@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
 abstract class FakeInvariantDeviceProfileTest {
 
     protected var context: Context? = null
@@ -49,6 +56,8 @@
     protected var isGestureMode: Boolean = true
     protected var isTransientTaskbar: Boolean = true
 
+    @Rule @JvmField val limitDevicesRule = LimitDevicesRule()
+
     @Before
     fun setUp() {
         context = ApplicationProvider.getApplicationContext()
@@ -148,7 +157,6 @@
 
                 numDatabaseHotseatIcons = 4
 
-                hotseatColumnSpan = IntArray(4) { 4 }
                 hotseatBarBottomSpace = FloatArray(4) { 48f }
                 hotseatQsbSpace = FloatArray(4) { 36f }
 
@@ -231,7 +239,6 @@
 
                 numDatabaseHotseatIcons = 6
 
-                hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
                 hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
                 hotseatQsbSpace = FloatArray(4) { 32f }
 
@@ -250,8 +257,10 @@
     }
 
     protected fun initializeVarsForTwoPanel(
-        isLandscape: Boolean = false,
-        isGestureMode: Boolean = true
+            isLandscape: Boolean = false,
+            isGestureMode: Boolean = true,
+            rows: Int = 4,
+            cols: Int = 4,
     ) {
         val (x, y) = if (isLandscape) Pair(2208, 1840) else Pair(1840, 2208)
 
@@ -267,9 +276,9 @@
 
         inv =
             InvariantDeviceProfile().apply {
-                numRows = 4
-                numColumns = 4
-                numSearchContainerColumns = 4
+                numRows = rows
+                numColumns = cols
+                numSearchContainerColumns = cols
 
                 iconSize = floatArrayOf(60f, 52f, 52f, 60f)
                 iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
@@ -310,7 +319,6 @@
 
                 numDatabaseHotseatIcons = 6
 
-                hotseatColumnSpan = IntArray(4) { 6 }
                 hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
                 hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
 
diff --git a/tests/src/com/android/launcher3/LauncherIntentTest.java b/tests/src/com/android/launcher3/LauncherIntentTest.java
new file mode 100644
index 0000000..aeeb42a
--- /dev/null
+++ b/tests/src/com/android/launcher3/LauncherIntentTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Intent;
+import android.platform.test.annotations.LargeTest;
+import android.view.KeyEvent;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.SearchRecyclerView;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class LauncherIntentTest extends AbstractLauncherUiTest<Launcher> {
+
+    public final Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS);
+
+    @Test
+    public void testAllAppsIntent() {
+        // Try executing ALL_APPS intent
+        executeOnLauncher(launcher -> launcher.onNewIntent(allAppsIntent));
+        // A-Z view with Main adapter should be loaded
+        assertOnMainAdapterAToZView();
+
+
+        // Try Moving to search view now
+        moveToSearchView();
+        // Try executing ALL_APPS intent
+        executeOnLauncher(launcher -> launcher.onNewIntent(allAppsIntent));
+        // A-Z view with Main adapter should be loaded
+        assertOnMainAdapterAToZView();
+    }
+
+    // Highlights the search bar, then fills text to display the SearchView.
+    private void moveToSearchView() {
+        // All Apps view should be loaded
+        assertTrue("Launcher internal state is not All Apps",
+                isInState(() -> LauncherState.ALL_APPS));
+        executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+        // Search view should be in focus
+        waitForLauncherCondition("Search view is not in focus.",
+                launcher -> launcher.getAppsView().getSearchView().hasFocus());
+        mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_C, 0);
+        // Upon key press, search recycler view should be loaded
+        waitForLauncherCondition("Search view not active.",
+                launcher -> launcher.getAppsView().getActiveRecyclerView()
+                        instanceof SearchRecyclerView);
+        mLauncher.unpressKeyCode(KeyEvent.KEYCODE_C, 0);
+    }
+
+    // Checks if main adapter view is selected, search bar is out of focus and scroller is at start.
+    private void assertOnMainAdapterAToZView() {
+        // All Apps State should be loaded
+        assertTrue("Launcher internal state is not All Apps",
+                isInState(() -> LauncherState.ALL_APPS));
+
+        // A-Z recycler view should be active.
+        waitForLauncherCondition("A-Z view not active.",
+                launcher -> !(launcher.getAppsView().getActiveRecyclerView()
+                        instanceof SearchRecyclerView));
+        // Personal Adapter should be selected.
+        waitForLauncherCondition("Not on Main Adapter View",
+                launcher -> launcher.getAppsView().getCurrentPage()
+                        == ActivityAllAppsContainerView.AdapterHolder.MAIN);
+        // Search view should not be in focus
+        waitForLauncherCondition("Search view has focus.",
+                launcher -> !launcher.getAppsView().getSearchView().hasFocus());
+        // Scroller should be at top
+        executeOnLauncher(launcher -> assertEquals(
+                "All Apps started in already scrolled state", 0,
+                getAllAppsScroll(launcher)));
+    }
+}
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index 88a430b..b813095 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -25,8 +25,6 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
-import org.junit.AfterClass
-import org.junit.BeforeClass
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -48,20 +46,6 @@
     private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
     private val launcherPrefs by lazy { LauncherPrefs.get(context) }
 
-    companion object {
-        @BeforeClass
-        @JvmStatic
-        fun setup() {
-            moveStartupDataToDeviceProtectedStorageIsEnabled = true
-        }
-
-        @AfterClass
-        @JvmStatic
-        fun teardown() {
-            moveStartupDataToDeviceProtectedStorageIsEnabled = false
-        }
-    }
-
     @Test
     fun has_keyMissingFromLauncherPrefs_returnsFalse() {
         assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
@@ -223,31 +207,12 @@
     }
 
     @Test
-    fun put_bootAwareItem_updatesEncryptedStorage() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-        encryptedPrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
-
-        launcherPrefs.putSync(bootAwareItem.to(TEST_STRING_ITEM.defaultValue))
-        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
-
-        launcherPrefs.removeSync(bootAwareItem)
-    }
-
-    @Test
     fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
         val bootAwareItem =
             LauncherPrefs.backedUpItem(
                 TEST_PREF_KEY,
                 TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
+                EncryptionType.DEVICE_PROTECTED
             )
 
         val bootAwarePrefs: SharedPreferences =
@@ -263,90 +228,4 @@
         launcherPrefs.removeSync(bootAwareItem)
         assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
     }
-
-    @Test
-    fun remove_bootAwareItem_removesFromEncryptedStorage() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
-            .commit()
-
-        launcherPrefs.removeSync(bootAwareItem)
-        assertThat(encryptedPrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
-    }
-
-    @Test
-    fun migrate_bootAwareItemsToDeviceProtectedStorage_worksAsIntended() {
-        val bootAwareItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY,
-                TEST_DEFAULT_VALUE,
-                EncryptionType.MOVE_TO_DEVICE_PROTECTED
-            )
-        launcherPrefs.removeSync(bootAwareItem)
-
-        val bootAwarePrefs: SharedPreferences =
-            context
-                .createDeviceProtectedStorageContext()
-                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
-
-        if (bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)) {
-            bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
-        }
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(bootAwareItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
-            .commit()
-
-        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
-        assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
-
-        launcherPrefs.removeSync(bootAwareItem)
-    }
-
-    @Test
-    fun migrate_onlyEncryptedItemsToDeviceProtectedStorage_doesNotHappen() {
-        val onlyEncryptedItem =
-            LauncherPrefs.backedUpItem(
-                TEST_PREF_KEY + "_",
-                TEST_DEFAULT_VALUE + "_",
-                EncryptionType.ENCRYPTED
-            )
-
-        val bootAwarePrefs: SharedPreferences =
-            context
-                .createDeviceProtectedStorageContext()
-                .getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
-
-        if (bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)) {
-            bootAwarePrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
-        }
-
-        val encryptedPrefs: SharedPreferences =
-            context.getSharedPreferences(onlyEncryptedItem.sharedPrefFile, Context.MODE_PRIVATE)
-
-        encryptedPrefs
-            .edit()
-            .putString(onlyEncryptedItem.sharedPrefKey, onlyEncryptedItem.defaultValue)
-            .commit()
-
-        launcherPrefs.migrateStartupDataToDeviceProtectedStorage()
-        assertThat(bootAwarePrefs.contains(onlyEncryptedItem.sharedPrefKey)).isFalse()
-
-        encryptedPrefs.edit().remove(onlyEncryptedItem.sharedPrefKey).commit()
-    }
 }
diff --git a/tests/src/com/android/launcher3/UtilitiesKtTest.kt b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
new file mode 100644
index 0000000..dd83871
--- /dev/null
+++ b/tests/src/com/android/launcher3/UtilitiesKtTest.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER
+import com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER
+import com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree
+import com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.views.WidgetsEduView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UtilitiesKtTest {
+
+    val context: Context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+    private lateinit var rootView: WidgetsEduView
+    private lateinit var midView: ViewGroup
+    private lateinit var childView: View
+    @Before
+    fun setup() {
+        rootView =
+            LayoutInflater.from(context).inflate(R.layout.widgets_edu, null) as WidgetsEduView
+        midView = rootView.requireViewById(R.id.edu_view)
+        childView = rootView.requireViewById(R.id.edu_header)
+    }
+
+    @Test
+    fun set_clipChildren_false() {
+        assertThat(rootView.clipChildren).isTrue()
+        assertThat(midView.clipChildren).isTrue()
+
+        modifyAttributesOnViewTree(childView, rootView, CLIP_CHILDREN_FALSE_MODIFIER)
+
+        assertThat(rootView.clipChildren).isFalse()
+        assertThat(midView.clipChildren).isFalse()
+    }
+
+    @Test
+    fun restore_clipChildren_true() {
+        assertThat(rootView.clipChildren).isTrue()
+        assertThat(midView.clipChildren).isTrue()
+        modifyAttributesOnViewTree(childView, rootView, CLIP_CHILDREN_FALSE_MODIFIER)
+        assertThat(rootView.clipChildren).isFalse()
+        assertThat(midView.clipChildren).isFalse()
+
+        restoreAttributesOnViewTree(childView, rootView, CLIP_CHILDREN_FALSE_MODIFIER)
+
+        assertThat(rootView.clipChildren).isTrue()
+        assertThat(midView.clipChildren).isTrue()
+    }
+
+    @Test
+    fun restore_clipChildren_skipRestoreMidView() {
+        assertThat(rootView.clipChildren).isTrue()
+        assertThat(midView.clipChildren).isTrue()
+        rootView.clipChildren = false
+        modifyAttributesOnViewTree(childView, rootView, CLIP_CHILDREN_FALSE_MODIFIER)
+        assertThat(rootView.clipChildren).isFalse()
+        assertThat(midView.clipChildren).isFalse()
+
+        restoreAttributesOnViewTree(childView, rootView, CLIP_CHILDREN_FALSE_MODIFIER)
+
+        assertThat(rootView.clipChildren).isFalse()
+        assertThat(midView.clipChildren).isTrue()
+    }
+
+    @Test
+    fun set_clipToPadding_false() {
+        assertThat(rootView.clipToPadding).isTrue()
+        assertThat(midView.clipToPadding).isTrue()
+
+        modifyAttributesOnViewTree(childView, rootView, CLIP_TO_PADDING_FALSE_MODIFIER)
+
+        assertThat(rootView.clipToPadding).isFalse()
+        assertThat(midView.clipToPadding).isFalse()
+    }
+
+    @Test
+    fun restore_clipToPadding_true() {
+        assertThat(rootView.clipToPadding).isTrue()
+        assertThat(midView.clipToPadding).isTrue()
+        modifyAttributesOnViewTree(childView, rootView, CLIP_TO_PADDING_FALSE_MODIFIER)
+        assertThat(rootView.clipToPadding).isFalse()
+        assertThat(midView.clipToPadding).isFalse()
+
+        restoreAttributesOnViewTree(childView, rootView, CLIP_TO_PADDING_FALSE_MODIFIER)
+
+        assertThat(rootView.clipToPadding).isTrue()
+        assertThat(midView.clipToPadding).isTrue()
+    }
+}
diff --git a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
index 259f519..d2238ff 100644
--- a/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
+++ b/tests/src/com/android/launcher3/allapps/AlphabeticalAppsListTest.java
@@ -19,6 +19,10 @@
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_LEFT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_BOTTOM_RIGHT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
@@ -60,7 +64,10 @@
 
     private static final int PRIVATE_SPACE_HEADER_ITEM_COUNT = 1;
     private static final int MAIN_USER_APP_COUNT = 2;
-    private static final int PRIVATE_USER_APP_COUNT = 1;
+    private static final int PRIVATE_USER_APP_COUNT = 2;
+    private static final int NUM_APP_COLS = 4;
+    private static final int NUM_APP_ROWS = 3;
+    private static final int PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT = 1;
 
     private AlphabeticalAppsList<?> mAlphabeticalAppsList;
     @Mock
@@ -81,6 +88,7 @@
                 info != null && info.user.equals(PRIVATE_HANDLE));
         mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
                 null, mPrivateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
     }
 
     @Test
@@ -90,6 +98,10 @@
         when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
                 .thenAnswer(answer(this::addPrivateSpaceHeader));
         when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(any()))
+                .thenReturn(iteminfo -> iteminfo.componentName == null
+                        || !iteminfo.componentName.getPackageName()
+                        .equals("com.android.launcher3.tests.camera"));
 
         mAlphabeticalAppsList.updateItemFilter(info -> info != null
                 && info.user.equals(MAIN_HANDLE));
@@ -106,6 +118,44 @@
     }
 
     @Test
+    public void privateProfileEnabled_privateProfileAppsShownWithSeparator() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
+        mSetFlagsRule.enableFlags(Flags.FLAG_PRIVATE_SPACE_SYS_APPS_SEPARATION);
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
+        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+                .thenAnswer(answer(this::addPrivateSpaceHeader));
+        when(mPrivateProfileManager.addSystemAppsDivider(any()))
+                .thenAnswer(answer(this::addSystemAppsDivider));
+        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps(mContext))
+                .thenReturn(iteminfo -> iteminfo.componentName == null
+                        || !iteminfo.componentName.getPackageName()
+                        .equals("com.android.launcher3.tests.camera"));
+
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        assertEquals(MAIN_USER_APP_COUNT + PRIVATE_SPACE_HEADER_ITEM_COUNT
+                + PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT
+                + PRIVATE_USER_APP_COUNT, mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(PRIVATE_SPACE_HEADER_ITEM_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER).toList().size());
+        assertEquals(PRIVATE_SPACE_SYS_APP_SEPARATOR_ITEM_COUNT,
+                mAlphabeticalAppsList.getAdapterItems().stream().filter(item ->
+                        item.viewType == VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER).toList().size());
+        List<BaseAllAppsAdapter.AdapterItem> psApps = mAlphabeticalAppsList.getAdapterItems()
+                .stream()
+                .filter(item -> item.itemInfo != null && item.itemInfo.user.equals(PRIVATE_HANDLE))
+                .toList();
+        assertEquals(PRIVATE_USER_APP_COUNT, psApps.size());
+        assert psApps.get(0).itemInfo.title != null;
+        assertEquals("Private Messenger", psApps.get(0).itemInfo.title.toString());
+        assert psApps.get(1).itemInfo.title != null;
+        assertEquals("Private Camera", psApps.get(1).itemInfo.title.toString());
+    }
+
+    @Test
     public void privateProfileDisabled_onlyPrivateProfileHeaderViewIsPresent() {
         mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_PRIVATE_SPACE);
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoListForMainAndPrivateUser());
@@ -182,11 +232,105 @@
                 .toList().size());
     }
 
+    @Test
+    public void getRoundRegions_whenIndexIsMiddleOfLastRow_roundNothing() {
+        int index = 3;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_NOTHING, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInEndOfLastRow_roundBottomRight() {
+        int index = 11;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_BOTTOM_RIGHT, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInBeginningOfLastRow_roundBottomLeft() {
+        int index = 8;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_BOTTOM_LEFT, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInMiddleOfLastRow_roundNothing() {
+        int index = 9;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_NOTHING, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInMiddleRow_roundNothing() {
+        int index = 5;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_NOTHING, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInBeginningOfTopRow_roundNothing() {
+        int index = 0;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_NOTHING, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInLastOfTopRow_roundNothing() {
+        int index = 3;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index,
+                NUM_APP_COLS * NUM_APP_ROWS);
+
+        assertEquals(ROUND_NOTHING, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInMiddleOfLastRowLastItem_roundBottomRight() {
+        int index = 9;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index, index+1);
+
+        assertEquals(ROUND_BOTTOM_RIGHT, roundRegions);
+    }
+
+    @Test
+    public void getRoundRegions_whenIndexIsInBeginningOfLastRowLastItem_roundBottomRight() {
+        int index = 8;
+
+        int roundRegions = mAlphabeticalAppsList.getRoundRegions(index, index+1);
+
+        assertEquals(ROUND_BOTTOM_RIGHT | ROUND_BOTTOM_LEFT, roundRegions);
+    }
+
     private int addPrivateSpaceHeader(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
         adapterItemList.add(new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_PRIVATE_SPACE_HEADER));
         return adapterItemList.size();
     }
 
+    private int addSystemAppsDivider(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
+        adapterItemList.add(new BaseAllAppsAdapter
+                .AdapterItem(VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER));
+        return adapterItemList.size();
+    }
+
     private AppInfo[] createAppInfoListForMainUser() {
         ComponentName gmailComponentName = new ComponentName(mContext,
                 "com.android.launcher3.tests.Activity" + "Gmail");
@@ -204,7 +348,11 @@
                 "com.android.launcher3.tests.Activity" + "PrivateMessenger");
         AppInfo privateMessengerAppInfo = new AppInfo(privateMessengercomponentName,
                 "Private Messenger", PRIVATE_HANDLE, new Intent());
-        return new AppInfo[]{privateMessengerAppInfo};
+        ComponentName privateCameraComponentName = new ComponentName(
+                "com.android.launcher3.tests.camera", "CameraActivity");
+        AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName,
+                "Private Camera", PRIVATE_HANDLE, new Intent());
+        return new AppInfo[]{privateMessengerAppInfo, privateCameraAppInfo};
     }
 
     private AppInfo[] createAppInfoListForMainAndPrivateUser() {
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 79d00c9..2a4d21d 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -16,22 +16,30 @@
 
 package com.android.launcher3.allapps;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
 import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -40,34 +48,40 @@
 
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.ApiWrapper;
 import com.android.launcher3.util.UserIconInfo;
+import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 
 @RunWith(AndroidJUnit4.class)
 public class PrivateProfileManagerTest {
 
+    @Rule(order = 0)
+    public TestRule testStabilityRule = new TestStabilityRule();
+
     private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
     private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
     private static final UserIconInfo MAIN_ICON_INFO =
             new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
     private static final UserIconInfo PRIVATE_ICON_INFO =
             new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
-    private static final String SAFETY_CENTER_INTENT = Intent.ACTION_SAFETY_CENTER;
-    private static final String PS_SETTINGS_FRAGMENT_KEY = ":settings:fragment_args_key";
-    private static final String PS_SETTINGS_FRAGMENT_VALUE = "AndroidPrivateSpace_personal";
 
     private PrivateProfileManager mPrivateProfileManager;
     @Mock
-    private ActivityAllAppsContainerView mActivityAllAppsContainerView;
+    private ActivityAllAppsContainerView mAllApps;
     @Mock
     private StatsLogManager mStatsLogManager;
     @Mock
@@ -77,9 +91,15 @@
     @Mock
     private Context mContext;
     @Mock
-    private AllAppsStore mAllAppsStore;
+    private AllAppsStore<?> mAllAppsStore;
     @Mock
     private PackageManager mPackageManager;
+    @Mock
+    private LauncherApps mLauncherApps;
+    @Mock
+    private AllAppsRecyclerView mAllAppsRecyclerView;
+    @Mock
+    private Resources mResources;
 
     @Before
     public void setUp() {
@@ -88,12 +108,22 @@
                 .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
         when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
         when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
-        when(mActivityAllAppsContainerView.getContext()).thenReturn(mContext);
-        when(mActivityAllAppsContainerView.getAppsStore()).thenReturn(mAllAppsStore);
+        when(mAllApps.getContext()).thenReturn(mContext);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getApplicationContext()).thenReturn(getApplicationContext());
+        when(mAllApps.getAppsStore()).thenReturn(mAllAppsStore);
+        when(mAllApps.getActiveRecyclerView()).thenReturn(mAllAppsRecyclerView);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.resolveActivity(any(), any())).thenReturn(new ResolveInfo());
+        when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
+        when(mLauncherApps.getAppMarketActivityIntent(any(), any())).thenReturn(PendingIntent
+                .getActivity(new ActivityContextWrapper(getApplicationContext()), 0,
+                        new Intent(), PendingIntent.FLAG_IMMUTABLE).getIntentSender());
+        when(mContext.getPackageName())
+                .thenReturn("com.android.launcher3.tests.privateProfileManager");
+        when(mLauncherApps.getPreInstalledSystemPackages(any())).thenReturn(new ArrayList<>());
         mPrivateProfileManager = new PrivateProfileManager(mUserManager,
-                mActivityAllAppsContainerView, mStatsLogManager, mUserCache);
+                mAllApps, mStatsLogManager, mUserCache);
     }
 
     @Test
@@ -120,31 +150,71 @@
     public void quietModeFlagPresent_privateSpaceIsResetToDisabled() {
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+        doNothing().when(privateProfileManager).executeLock();
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(false, true);
 
         // In first call the state should be disabled.
         privateProfileManager.reset();
-        assertEquals(STATE_ENABLED, privateProfileManager.getCurrentState());
+        assertEquals("Profile State is not Disabled", STATE_ENABLED,
+                privateProfileManager.getCurrentState());
 
         // In the next call the state should be disabled.
         privateProfileManager.reset();
-        assertEquals(STATE_DISABLED, privateProfileManager.getCurrentState());
+        assertEquals("Profile State is not Disabled", STATE_DISABLED,
+                privateProfileManager.getCurrentState());
     }
 
     @Test
-    public void openPrivateSpaceSettings_triggersSecurityAndPrivacyIntent() {
-        Intent expectedIntent = new Intent(SAFETY_CENTER_INTENT);
-        expectedIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
-        ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320703862
+    public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
+        when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
+                .thenReturn(false);
+        doNothing().when(privateProfileManager).expandPrivateSpace();
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
 
-        mPrivateProfileManager.openPrivateSpaceSettings();
+        privateProfileManager.unlockPrivateProfile();
+        privateProfileManager.reset();
+
+        awaitTasksCompleted();
+        Mockito.verify(privateProfileManager).postUnlock();
+    }
+
+    @Test
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+    public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+        doNothing().when(privateProfileManager).executeLock();
+        doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
+        when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
+                .thenReturn(true);
+        doNothing().when(privateProfileManager).expandPrivateSpace();
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+
+        privateProfileManager.lockPrivateProfile();
+        privateProfileManager.reset();
+
+        awaitTasksCompleted();
+        Mockito.verify(privateProfileManager).executeLock();
+    }
+
+    @Test
+    public void openPrivateSpaceSettings_triggersCorrectIntent() {
+        Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent();
+        ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
+        mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
+
+        mPrivateProfileManager.openPrivateSpaceSettings(null);
 
         Mockito.verify(mContext).startActivity(acIntent.capture());
-        Intent actualIntent = acIntent.getValue();
-        assertEquals(expectedIntent.getAction(), actualIntent.getAction());
-        assertEquals(expectedIntent.getStringExtra(PS_SETTINGS_FRAGMENT_KEY),
-                actualIntent.getStringExtra(PS_SETTINGS_FRAGMENT_KEY));
+        assertEquals("Intent Action is different",
+                expectedIntent == null ? null : expectedIntent.toUri(0),
+                acIntent.getValue() == null ? null : acIntent.getValue().toUri(0));
     }
 
     private static void awaitTasksCompleted() throws Exception {
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
deleted file mode 100644
index bc09cdd..0000000
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
-import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
-import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.launcher3.R;
-import com.android.launcher3.util.ActivityContextWrapper;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class PrivateSpaceHeaderViewControllerTest {
-
-    private static final int CONTAINER_HEADER_ELEMENT_COUNT = 1;
-    private static final int LOCK_UNLOCK_BUTTON_COUNT = 1;
-    private static final int PS_SETTINGS_BUTTON_COUNT_VISIBLE = 1;
-    private static final int PS_SETTINGS_BUTTON_COUNT_INVISIBLE = 0;
-    private static final int PS_TRANSITION_IMAGE_COUNT = 1;
-
-    private Context mContext;
-    private LayoutInflater mLayoutInflater;
-    private PrivateSpaceHeaderViewController mPsHeaderViewController;
-    private RelativeLayout mPsHeaderLayout;
-    @Mock
-    private PrivateProfileManager mPrivateProfileManager;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = new ActivityContextWrapper(getApplicationContext());
-        mLayoutInflater = LayoutInflater.from(getApplicationContext());
-        mPsHeaderViewController = new PrivateSpaceHeaderViewController(mPrivateProfileManager);
-        mPsHeaderLayout = (RelativeLayout) mLayoutInflater.inflate(R.layout.private_space_header,
-                null);
-    }
-
-    @Test
-    public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
-        Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.bg_ps_unlock_button));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
-        awaitTasksCompleted();
-
-        int totalContainerHeaderView = 0;
-        int totalLockUnlockButtonView = 0;
-        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
-            View view = mPsHeaderLayout.getChildAt(i);
-            if (view.getId() == R.id.ps_container_header) {
-                totalContainerHeaderView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-            } else if (view.getId() == R.id.ps_lock_unlock_button
-                    && view instanceof ImageView imageView) {
-                totalLockUnlockButtonView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-                getBitmap(imageView.getDrawable()).sameAs(unlockButton);
-            } else {
-                assertEquals(View.GONE, view.getVisibility());
-            }
-        }
-        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
-        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
-    }
-
-    @Test
-    public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
-        Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
-        Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_settings_button));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
-        awaitTasksCompleted();
-
-        int totalContainerHeaderView = 0;
-        int totalLockUnlockButtonView = 0;
-        int totalSettingsImageView = 0;
-        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
-            View view = mPsHeaderLayout.getChildAt(i);
-            if (view.getId() == R.id.ps_container_header) {
-                totalContainerHeaderView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-            } else if (view.getId() == R.id.ps_lock_unlock_button
-                    && view instanceof ImageView imageView) {
-                totalLockUnlockButtonView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-                getBitmap(imageView.getDrawable()).sameAs(lockImage);
-            } else if (view.getId() == R.id.ps_settings_button
-                    && view instanceof ImageView imageView) {
-                totalSettingsImageView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-                getBitmap(imageView.getDrawable()).sameAs(settingsImage);
-            } else {
-                assertEquals(View.GONE, view.getVisibility());
-            }
-        }
-        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
-        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
-        assertEquals(PS_SETTINGS_BUTTON_COUNT_VISIBLE, totalSettingsImageView);
-    }
-
-    @Test
-    public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
-            throws Exception {
-        Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
-        awaitTasksCompleted();
-
-        int totalContainerHeaderView = 0;
-        int totalLockUnlockButtonView = 0;
-        int totalSettingsImageView = 0;
-        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
-            View view = mPsHeaderLayout.getChildAt(i);
-            if (view.getId() == R.id.ps_container_header) {
-                totalContainerHeaderView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-            } else if (view.getId() == R.id.ps_lock_unlock_button
-                    && view instanceof ImageView imageView) {
-                totalLockUnlockButtonView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-                getBitmap(imageView.getDrawable()).sameAs(lockImage);
-            } else {
-                assertEquals(View.GONE, view.getVisibility());
-            }
-        }
-        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
-        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
-        assertEquals(PS_SETTINGS_BUTTON_COUNT_INVISIBLE, totalSettingsImageView);
-    }
-
-    @Test
-    public void privateProfileTransitioning_psHeaderContainsTransitionView() throws Exception {
-        Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
-        awaitTasksCompleted();
-
-        int totalContainerHeaderView = 0;
-        int totalLockUnlockButtonView = 0;
-        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
-            View view = mPsHeaderLayout.getChildAt(i);
-            if (view.getId() == R.id.ps_container_header) {
-                totalContainerHeaderView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-            } else if (view.getId() == R.id.ps_transition_image
-                    && view instanceof ImageView imageView) {
-                totalLockUnlockButtonView += 1;
-                assertEquals(View.VISIBLE, view.getVisibility());
-                getBitmap(imageView.getDrawable()).sameAs(transitionImage);
-            } else {
-                assertEquals(View.GONE, view.getVisibility());
-            }
-        }
-        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
-        assertEquals(PS_TRANSITION_IMAGE_COUNT, totalLockUnlockButtonView);
-    }
-
-    private Bitmap getBitmap(Drawable drawable) {
-        Bitmap result;
-        if (drawable instanceof BitmapDrawable) {
-            result = ((BitmapDrawable) drawable).getBitmap();
-        } else {
-            int width = drawable.getIntrinsicWidth();
-            int height = drawable.getIntrinsicHeight();
-            // Some drawables have no intrinsic width - e.g. solid colours.
-            if (width <= 0) {
-                width = 1;
-            }
-            if (height <= 0) {
-                height = 1;
-            }
-
-            result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-            Canvas canvas = new Canvas(result);
-            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
-            drawable.draw(canvas);
-        }
-        return result;
-    }
-
-    private static void awaitTasksCompleted() throws Exception {
-        UI_HELPER_EXECUTOR.submit(() -> null).get();
-    }
-}
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
new file mode 100644
index 0000000..512b2ac
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -0,0 +1,467 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.allapps;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.UserIconInfo;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PrivateSpaceHeaderViewTest {
+
+    private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
+    private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+    private static final UserIconInfo MAIN_ICON_INFO =
+            new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
+    private static final UserIconInfo PRIVATE_ICON_INFO =
+            new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
+    private static final String CAMERA_PACKAGE_NAME = "com.android.launcher3.tests.camera";
+    private static final int CONTAINER_HEADER_ELEMENT_COUNT = 1;
+    private static final int LOCK_UNLOCK_BUTTON_COUNT = 1;
+    private static final int PS_SETTINGS_BUTTON_COUNT_VISIBLE = 1;
+    private static final int PS_SETTINGS_BUTTON_COUNT_INVISIBLE = 0;
+    private static final int PS_TRANSITION_IMAGE_COUNT = 1;
+    private static final int NUM_APP_COLS = 4;
+    private static final int NUM_PRIVATE_SPACE_APPS = 50;
+    private static final int ALL_APPS_HEIGHT = 10;
+    private static final int ALL_APPS_CELL_HEIGHT = 1;
+    private static final int PS_HEADER_HEIGHT = 1;
+    private static final int BIGGER_PS_HEADER_HEIGHT = 2;
+    private static final int SCROLL_NO_WHERE = -1;
+    private static final float HEADER_PROTECTION_HEIGHT = 1F;
+
+    private Context mContext;
+    private RelativeLayout mPsHeaderLayout;
+    private AlphabeticalAppsList<?> mAlphabeticalAppsList;
+    private PrivateProfileManager mPrivateProfileManager;
+    @Mock
+    private ActivityAllAppsContainerView mAllApps;
+    @Mock
+    private AllAppsStore<?> mAllAppsStore;
+    @Mock
+    private UserCache mUserCache;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private StatsLogManager mStatsLogManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = new ActivityContextWrapper(getApplicationContext());
+        when(mAllApps.getContext()).thenReturn(mContext);
+        when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
+        when(mUserCache.getUserProfiles())
+                .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
+        when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
+        mPrivateProfileManager = new PrivateProfileManager(mUserManager,
+                mAllApps, mStatsLogManager, mUserCache);
+        mPsHeaderLayout = (RelativeLayout) LayoutInflater.from(mContext).inflate(
+                R.layout.private_space_header, null);
+    }
+
+    @Test
+    public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
+        Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
+
+        int totalContainerHeaderView = 0;
+        int totalLockUnlockButtonView = 0;
+        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
+            View view = mPsHeaderLayout.getChildAt(i);
+            if (view.getId() == R.id.ps_container_header) {
+                totalContainerHeaderView += 1;
+                assertEquals(View.VISIBLE, view.getVisibility());
+            } else if (view.getId() == R.id.settingsAndLockGroup) {
+                ImageView lockIcon = view.findViewById(R.id.lock_icon);
+                assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(unlockButton));
+                assertEquals(View.VISIBLE, lockIcon.getVisibility());
+
+                // Verify textView shouldn't be showing when disabled.
+                TextView lockText = view.findViewById(R.id.lock_text);
+                assertEquals(View.GONE, lockText.getVisibility());
+                totalLockUnlockButtonView += 1;
+            } else {
+                assertEquals(View.GONE, view.getVisibility());
+            }
+        }
+
+        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
+        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
+    }
+
+    @Test
+    public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
+        Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
+        Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.ic_ps_settings));
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
+
+        int totalContainerHeaderView = 0;
+        int totalLockUnlockButtonView = 0;
+        int totalSettingsImageView = 0;
+        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
+            View view = mPsHeaderLayout.getChildAt(i);
+            if (view.getId() == R.id.ps_container_header) {
+                totalContainerHeaderView += 1;
+                assertEquals(View.VISIBLE, view.getVisibility());
+            } else if (view.getId() == R.id.settingsAndLockGroup) {
+                // Look for settings button.
+                ImageButton settingsButton = view.findViewById(R.id.ps_settings_button);
+                assertEquals(View.VISIBLE, settingsButton.getVisibility());
+                totalSettingsImageView += 1;
+                assertTrue(getBitmap(settingsButton.getDrawable()).sameAs(settingsImage));
+
+                // Look for lock_icon and lock_text.
+                ImageView lockIcon = view.findViewById(R.id.lock_icon);
+                assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(lockImage));
+                assertEquals(View.VISIBLE, lockIcon.getVisibility());
+                TextView lockText = view.findViewById(R.id.lock_text);
+                assertEquals(View.VISIBLE, lockText.getVisibility());
+                totalLockUnlockButtonView += 1;
+            } else {
+                assertEquals(View.GONE, view.getVisibility());
+            }
+        }
+
+        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
+        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
+        assertEquals(PS_SETTINGS_BUTTON_COUNT_VISIBLE, totalSettingsImageView);
+    }
+
+    @Test
+    public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
+            throws Exception {
+        Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
+
+        int totalContainerHeaderView = 0;
+        int totalLockUnlockButtonView = 0;
+        int totalSettingsImageView = 0;
+        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
+            View view = mPsHeaderLayout.getChildAt(i);
+            if (view.getId() == R.id.ps_container_header) {
+                totalContainerHeaderView += 1;
+                assertEquals(View.VISIBLE, view.getVisibility());
+            } else if (view.getId() == R.id.settingsAndLockGroup) {
+                // Ensure there is no settings button.
+                ImageButton settingsImage = view.findViewById(R.id.ps_settings_button);
+                assertEquals(View.GONE, settingsImage.getVisibility());
+
+                // Check lock icon and lock text is there.
+                ImageView lockIcon = view.findViewById(R.id.lock_icon);
+                assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(lockImage));
+                assertEquals(View.VISIBLE, lockIcon.getVisibility());
+                TextView lockText = view.findViewById(R.id.lock_text);
+                assertEquals(View.VISIBLE, lockText.getVisibility());
+                totalLockUnlockButtonView += 1;
+            } else {
+                assertEquals(View.GONE, view.getVisibility());
+            }
+        }
+
+        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
+        assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
+        assertEquals(PS_SETTINGS_BUTTON_COUNT_INVISIBLE, totalSettingsImageView);
+    }
+
+    @Test
+    public void privateProfileTransitioning_psHeaderContainsTransitionView() throws Exception {
+        Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        awaitTasksCompleted();
+
+        int totalContainerHeaderView = 0;
+        int totalLockUnlockButtonView = 0;
+        for (int i = 0; i < mPsHeaderLayout.getChildCount(); i++) {
+            View view = mPsHeaderLayout.getChildAt(i);
+            if (view.getId() == R.id.ps_container_header) {
+                totalContainerHeaderView += 1;
+                assertEquals(View.VISIBLE, view.getVisibility());
+            } else if (view.getId() == R.id.ps_transition_image
+                    && view instanceof ImageView imageView) {
+                totalLockUnlockButtonView += 1;
+                assertEquals(View.VISIBLE, view.getVisibility());
+                assertTrue(getBitmap(imageView.getDrawable()).sameAs(transitionImage));
+            } else if (view.getId() == R.id.settingsAndLockGroup) {
+                LinearLayout lockUnlockButton = view.findViewById(R.id.ps_lock_unlock_button);
+                assertEquals(View.GONE, lockUnlockButton.getVisibility());
+            } else {
+                assertEquals(View.GONE, view.getVisibility());
+            }
+        }
+
+        assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
+        assertEquals(PS_TRANSITION_IMAGE_COUNT, totalLockUnlockButtonView);
+    }
+
+    @Test
+    public void scrollForViewToBeVisibleInContainer_withHeader() {
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+                .addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
+        when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+        when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        when(mAllApps.isUsingTabs()).thenReturn(true);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
+        int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+        // The number of adapterItems should be the private space apps + one main app + header.
+        assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(position,
+                privateProfileManager.scrollForHeaderToBeVisibleInContainer(
+                        new AllAppsRecyclerView(mContext),
+                        mAlphabeticalAppsList.getAdapterItems(),
+                        PS_HEADER_HEIGHT,
+                        ALL_APPS_CELL_HEIGHT));
+    }
+
+    @Test
+    public void scrollForViewToBeVisibleInContainer_withHeaderNoTabs() {
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+                .addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
+        when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+        when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        when(mAllApps.isUsingTabs()).thenReturn(false);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT) - 1;
+        int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+        // The number of adapterItems should be the private space apps + one main app + header.
+        assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(position,
+                privateProfileManager.scrollForHeaderToBeVisibleInContainer(
+                        new AllAppsRecyclerView(mContext),
+                        mAlphabeticalAppsList.getAdapterItems(),
+                        PS_HEADER_HEIGHT,
+                        ALL_APPS_CELL_HEIGHT));
+    }
+
+    @Test
+    public void scrollForViewToBeVisibleInContainer_withHeaderAndLessAppRowSpace() {
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+                .addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
+        when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+        when(mAllApps.isUsingTabs()).thenReturn(true);
+        when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        int rows = (int) (ALL_APPS_HEIGHT - BIGGER_PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
+        int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+        // The number of adapterItems should be the private space apps + one main app + header.
+        assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(position,
+                privateProfileManager.scrollForHeaderToBeVisibleInContainer(
+                        new AllAppsRecyclerView(mContext),
+                        mAlphabeticalAppsList.getAdapterItems(),
+                        BIGGER_PS_HEADER_HEIGHT,
+                        ALL_APPS_CELL_HEIGHT));
+    }
+
+    @Test
+    public void scrollForViewToBeVisibleInContainer_withNoHeader() {
+        when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        doReturn(splitIntoUserInstalledAndSystemApps()).when(privateProfileManager)
+                .splitIntoUserInstalledAndSystemApps(any());
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
+        when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+        when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
+        // The number of adapterItems should be the private space apps + one main app.
+        assertEquals(NUM_PRIVATE_SPACE_APPS + 1,
+                mAlphabeticalAppsList.getAdapterItems().size());
+        assertEquals(SCROLL_NO_WHERE, privateProfileManager.scrollForHeaderToBeVisibleInContainer(
+                new AllAppsRecyclerView(mContext),
+                mAlphabeticalAppsList.getAdapterItems(),
+                BIGGER_PS_HEADER_HEIGHT,
+                ALL_APPS_CELL_HEIGHT));
+    }
+
+    private Bitmap getBitmap(Drawable drawable) {
+        Bitmap result;
+        if (drawable instanceof BitmapDrawable) {
+            result = ((BitmapDrawable) drawable).getBitmap();
+        } else {
+            int width = drawable.getIntrinsicWidth();
+            int height = drawable.getIntrinsicHeight();
+            // Some drawables have no intrinsic width - e.g. solid colours.
+            if (width <= 0) {
+                width = 1;
+            }
+            if (height <= 0) {
+                height = 1;
+            }
+
+            result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(result);
+            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+            drawable.draw(canvas);
+        }
+        return result;
+    }
+
+    private static void awaitTasksCompleted() throws Exception {
+        UI_HELPER_EXECUTOR.submit(() -> null).get();
+    }
+
+    private int addPrivateSpaceHeader(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
+        BaseAllAppsAdapter.AdapterItem privateSpaceHeader =
+                new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_PRIVATE_SPACE_HEADER);
+        adapterItemList.add(privateSpaceHeader);
+        return adapterItemList.size();
+    }
+
+    private AppInfo[] createAppInfoList() {
+        List<AppInfo> appInfos = new ArrayList<>();
+        ComponentName gmailComponentName = new ComponentName(mContext,
+                "com.android.launcher3.tests.Activity" + "Gmail");
+        AppInfo gmailAppInfo = new
+                AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
+        appInfos.add(gmailAppInfo);
+        ComponentName privateCameraComponentName = new ComponentName(
+                CAMERA_PACKAGE_NAME, "CameraActivity");
+        for (int i = 0; i < NUM_PRIVATE_SPACE_APPS; i++) {
+            AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName,
+                    "Private Camera " + i, PRIVATE_HANDLE, new Intent());
+            appInfos.add(privateCameraAppInfo);
+        }
+        return appInfos.toArray(AppInfo[]::new);
+    }
+
+    private Predicate<AppInfo> splitIntoUserInstalledAndSystemApps() {
+        return iteminfo -> iteminfo.componentName == null
+                || !iteminfo.componentName.getPackageName()
+                .equals(CAMERA_PACKAGE_NAME);
+    }
+}
diff --git a/tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
similarity index 87%
rename from tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java
rename to tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
index 9f6bbdf..0b233e5 100644
--- a/tests/src/com/android/launcher3/allapps/TaplTestsAllAppsIconsWorking.java
+++ b/tests/src/com/android/launcher3/allapps/TaplAllAppsIconsWorkingTest.java
@@ -15,31 +15,23 @@
  */
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
-
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.tapl.AppIcon;
 import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * The test runs in Out of process (Oop) and in process.
  * Makes sure the basic behaviors of Icons on AllApps are working.
  */
-public class TaplTestsAllAppsIconsWorking extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplAllAppsIconsWorkingTest extends AbstractLauncherUiTest<Launcher> {
 
     /**
      * Makes sure we can launch an icon from All apps
@@ -62,5 +54,6 @@
         } finally {
             allApps.unfreeze();
         }
+        mLauncher.goHome();
     }
 }
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
index ee32e97..20684eb 100644
--- a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
@@ -27,25 +26,19 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.launcher3.views.ActivityContext;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TaplKeyboardFocusTest extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplKeyboardFocusTest extends AbstractLauncherUiTest<Launcher> {
 
     @Test
     public void testAllAppsFocusApp() {
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
similarity index 91%
rename from tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
rename to tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index b4a5169..f3f6fa5 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -16,12 +16,10 @@
 package com.android.launcher3.allapps;
 
 import static com.android.launcher3.util.TestUtil.expectFail;
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.Intent;
@@ -30,34 +28,25 @@
 import androidx.test.filters.FlakyTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.tapl.AllApps;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 
-import org.junit.Before;
 import org.junit.Test;
 
 /**
  * Test that we can open and close the all apps in multiple situations.
  * The test runs in Out of process (Oop) and in process.
  */
-public class TaplOpenCloseAllApps extends AbstractLauncherUiTest {
+public class TaplOpenCloseAllAppsTest extends AbstractLauncherUiTest<Launcher> {
 
     public static final String READ_DEVICE_CONFIG_PERMISSION =
             "android.permission.READ_DEVICE_CONFIG";
 
     /**
-     * Calls static method initialize
-     */
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
-
-    /**
      * Make sure we can go home after pressing the context menu on an Icon on the AllApps.
      */
     @Test
@@ -130,6 +119,8 @@
      */
     @Test
     @PortraitLandscape
+    @PlatinumTest(focusArea = "launcher")
+    @ScreenRecordRule.ScreenRecord // b/322228038
     public void testAllAppsFromHome() {
         // Test opening all apps
         assertNotNull("switchToAllApps() returned null",
@@ -181,10 +172,10 @@
             executeOnLauncher(launcher -> assertTrue("flingBackward() didn't scroll App Apps",
                     flingBackwardY < flingForwardY));
 
-            // Test scrolling down to YouTube.
-            assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("YouTube"));
-            // Test scrolling up to Camera.
-            assertNotNull("All apps: can't find Camera", allApps.getAppIcon("Camera"));
+            // Test scrolling down to the end of the app list.
+            assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("ZZZ"));
+            // Test scrolling up to the beginning oof the app list.
+            assertNotNull("All apps: can't find Camera", allApps.getAppIcon("AAA"));
             // Test failing to find a non-existing app.
             final AllApps allAppsFinal = allApps;
             expectFail("All apps: could find a non-existing app",
@@ -207,15 +198,13 @@
     public void testPressBackFromAllAppsToHome() {
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
                 READ_DEVICE_CONFIG_PERMISSION);
-        assumeFalse(FeatureFlags.ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION.get());
         mLauncher
                 .getWorkspace()
                 .switchToAllApps()
                 .pressBackToWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
         startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
-        mLauncher.pressBack();
-        mLauncher.getWorkspace();
+        mLauncher.getLaunchedAppState().pressBackToWorkspace();
         waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
     }
 
diff --git a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
index a1f2cef..55d3252 100644
--- a/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
+++ b/tests/src/com/android/launcher3/appiconmenu/TaplAppIconMenuTest.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.appiconmenu;
 
 import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -32,7 +31,6 @@
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 
-import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -40,13 +38,7 @@
  * Tests the AppIconMenu (the menu that appears when you long press an app icon) and also make sure
  * we can launch a shortcut from it.
  */
-public class TaplAppIconMenuTest extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplAppIconMenuTest extends AbstractLauncherUiTest<Launcher> {
 
     private boolean isOptionsPopupVisible(Launcher launcher) {
         final ArrowPopup<?> popup = launcher.getOptionsPopup();
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
new file mode 100644
index 0000000..479b201
--- /dev/null
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.backuprestore
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.model.ModelDbController
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.TestUtil
+import com.android.launcher3.util.rule.BackAndRestoreRule
+import com.android.launcher3.util.rule.setFlags
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Makes sure to test {@code RestoreDbTask#removeOldDBs}, we need to remove all the dbs that are not
+ * the last one used when we restore the device.
+ */
+@RunWith(AndroidJUnit4::class)
+@MediumTest
+class BackupAndRestoreDBSelectionTest {
+
+    @JvmField @Rule var backAndRestoreRule = BackAndRestoreRule()
+
+    @JvmField
+    @Rule
+    val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+    @Before
+    fun setUp() {
+        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_NARROW_GRID_RESTORE)
+    }
+
+    @Test
+    fun oldDatabasesNotPresentAfterRestore() {
+        val dbController = ModelDbController(getInstrumentation().targetContext)
+        dbController.tryMigrateDB(null)
+        TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+            assert(backAndRestoreRule.getDatabaseFiles().size == 1) {
+                "There should only be one database after restoring, the last one used. Actual databases ${backAndRestoreRule.getDatabaseFiles()}"
+            }
+            assert(
+                !LauncherPrefs.get(getInstrumentation().targetContext)
+                    .has(LauncherPrefs.RESTORE_DEVICE)
+            ) {
+                "RESTORE_DEVICE shouldn't be present after a backup and restore."
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
index d8ae74b..9fb1989 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
@@ -41,7 +41,7 @@
 
                 CellPosMapper.CellPos pos = launcher.getCellPosMapper().mapPresenterToModel(
                         params.getCellX(), params.getCellY(),
-                        launcher.getWorkspace().getIdForScreen(cellLayout), CONTAINER_DESKTOP);
+                        launcher.getWorkspace().getCellLayoutId(cellLayout), CONTAINER_DESKTOP);
                 int screenId = pos.screenId;
                 for (int j = boards.size(); j <= screenId; j++) {
                     boards.add(new CellLayoutBoard(cellLayout.getCountX(), cellLayout.getCountY()));
diff --git a/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt b/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
new file mode 100644
index 0000000..13dfd5e
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/HotseatReorderUnitTest.kt
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.content.Context
+import android.graphics.Point
+import android.util.Log
+import android.view.View
+import androidx.core.view.get
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.CellLayout
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.celllayout.board.IconPoint
+import com.android.launcher3.celllayout.board.PermutedBoardComparator
+import com.android.launcher3.celllayout.board.WidgetRect
+import com.android.launcher3.celllayout.testgenerator.RandomBoardGenerator
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.views.DoubleShadowBubbleTextView
+import java.util.Random
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+private class HotseatReorderTestCase(
+    val startBoard: CellLayoutBoard,
+    val endBoard: CellLayoutBoard
+) {
+    override fun toString(): String {
+        return "$startBoard#endBoard:\n$endBoard"
+    }
+}
+
+class HotseatReorderUnitTest {
+
+    private val applicationContext: Context =
+        ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+    @JvmField @Rule var cellLayoutBuilder = UnitTestCellLayoutBuilderRule()
+
+    /**
+     * This test generates random CellLayout configurations and then try to reorder it and makes
+     * sure the result is a valid board meaning it didn't remove any widget or icon.
+     */
+    @Test
+    fun generateValidTests() {
+        val generator = Random(Companion.SEED.toLong())
+        for (i in 0 until Companion.TOTAL_OF_CASES_GENERATED) {
+            // Using a new seed so that we can replicate the same test cases.
+            val seed = generator.nextInt()
+            Log.d(Companion.TAG, "Seed = $seed")
+
+            val testCase: HotseatReorderTestCase =
+                generateRandomTestCase(RandomBoardGenerator(Random(seed.toLong())))
+            Log.d(Companion.TAG, "testCase = $testCase")
+
+            Assert.assertTrue(
+                "invalid case $i",
+                PermutedBoardComparator().compare(testCase.startBoard, testCase.endBoard) == 0
+            )
+        }
+    }
+
+    private fun addViewInCellLayout(
+        cellLayout: CellLayout,
+        cellX: Int,
+        cellY: Int,
+        spanX: Int,
+        spanY: Int,
+        isWidget: Boolean
+    ) {
+        val cell =
+            if (isWidget) View(applicationContext)
+            else DoubleShadowBubbleTextView(applicationContext)
+        cell.layoutParams = CellLayoutLayoutParams(cellX, cellY, spanX, spanY)
+        cellLayout.addViewToCellLayout(
+            cell,
+            -1,
+            cell.id,
+            cell.layoutParams as CellLayoutLayoutParams,
+            true
+        )
+    }
+
+    private fun solve(board: CellLayoutBoard): CellLayout {
+        val cl = cellLayoutBuilder.createCellLayout(board.width, board.height, false)
+        // The views have to be sorted or the result can vary
+        board.icons
+            .map(IconPoint::getCoord)
+            .sortedWith(
+                Comparator.comparing { p: Any -> (p as Point).x }
+                    .thenComparing { p: Any -> (p as Point).y }
+            )
+            .forEach { p ->
+                addViewInCellLayout(
+                    cellLayout = cl,
+                    cellX = p.x,
+                    cellY = p.y,
+                    spanX = 1,
+                    spanY = 1,
+                    isWidget = false
+                )
+            }
+        board.widgets
+            .sortedWith(
+                Comparator.comparing(WidgetRect::getCellX).thenComparing(WidgetRect::getCellY)
+            )
+            .forEach { widget ->
+                addViewInCellLayout(
+                    cl,
+                    widget.cellX,
+                    widget.cellY,
+                    widget.spanX,
+                    widget.spanY,
+                    isWidget = true
+                )
+            }
+        if (cl.makeSpaceForHotseatMigration(true)) {
+            commitTempPosition(cl)
+        }
+        return cl
+    }
+
+    private fun commitTempPosition(cellLayout: CellLayout) {
+        val count = cellLayout.shortcutsAndWidgets.childCount
+        for (i in 0 until count) {
+            val params = cellLayout.shortcutsAndWidgets[i].layoutParams as CellLayoutLayoutParams
+            params.cellX = params.tmpCellX
+            params.cellY = params.tmpCellY
+        }
+    }
+
+    private fun boardFromCellLayout(cellLayout: CellLayout): CellLayoutBoard {
+        val views = mutableListOf<View>()
+        for (i in 0 until cellLayout.shortcutsAndWidgets.childCount) {
+            views.add(cellLayout.shortcutsAndWidgets.getChildAt(i))
+        }
+        return CellLayoutTestUtils.viewsToBoard(views, cellLayout.countX, cellLayout.countY)
+    }
+
+    private fun generateRandomTestCase(
+        boardGenerator: RandomBoardGenerator
+    ): HotseatReorderTestCase {
+        val width: Int = boardGenerator.getRandom(3, Companion.MAX_BOARD_SIZE)
+        val height: Int = boardGenerator.getRandom(3, Companion.MAX_BOARD_SIZE)
+        val targetWidth: Int = boardGenerator.getRandom(1, width - 2)
+        val targetHeight: Int = boardGenerator.getRandom(1, height - 2)
+        val board: CellLayoutBoard =
+            boardGenerator.generateBoard(width, height, targetWidth * targetHeight)
+        val finishBoard: CellLayoutBoard = boardFromCellLayout(solve(board))
+        return HotseatReorderTestCase(board, finishBoard)
+    }
+
+    companion object {
+        private const val MAX_BOARD_SIZE = 13
+
+        /**
+         * There is nothing special about this numbers, the random seed is just to be able to
+         * reproduce the test cases and the height and width is a random number similar to what
+         * users expect on their devices
+         */
+        private const val SEED = -194162315
+        private const val TOTAL_OF_CASES_GENERATED = 300
+        private const val TAG = "HotseatReorderUnitTest"
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index e1af774..0ff7c20 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -29,8 +29,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.CellLayout;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.MultipageCellLayout;
 import com.android.launcher3.celllayout.board.CellLayoutBoard;
 import com.android.launcher3.celllayout.board.IconPoint;
@@ -41,8 +39,7 @@
 import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
 
-import org.junit.After;
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -70,7 +67,8 @@
     private static final int TOTAL_OF_CASES_GENERATED = 300;
     private Context mApplicationContext;
 
-    private int mPrevNumColumns, mPrevNumRows;
+    @Rule
+    public UnitTestCellLayoutBuilderRule mCellLayoutBuilder = new UnitTestCellLayoutBuilderRule();
 
     /**
      * This test reads existing test cases and makes sure the CellLayout produces the same
@@ -144,34 +142,10 @@
                 (CellLayoutLayoutParams) cell.getLayoutParams(), true);
     }
 
-    public CellLayout createCellLayout(int width, int height, boolean isMulti) {
-        Context c = mApplicationContext;
-        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
-        // modify the device profile.
-        dp.inv.numColumns = isMulti ? width / 2 : width;
-        dp.inv.numRows = height;
-        dp.cellLayoutBorderSpacePx = new Point(0, 0);
-
-        CellLayout cl = isMulti ? new MultipageCellLayout(getWrappedContext(c, dp))
-                : new CellLayout(getWrappedContext(c, dp));
-        // I put a very large number for width and height so that all the items can fit, it doesn't
-        // need to be exact, just bigger than the sum of cell border
-        cl.measure(View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY));
-        return cl;
-    }
-
-    private Context getWrappedContext(Context context, DeviceProfile dp) {
-        return new ActivityContextWrapper(context) {
-            public DeviceProfile getDeviceProfile() {
-                return dp;
-            }
-        };
-    }
-
     public ItemConfiguration solve(CellLayoutBoard board, int x, int y, int spanX,
             int spanY, int minSpanX, int minSpanY, boolean isMulti) {
-        CellLayout cl = createCellLayout(board.getWidth(), board.getHeight(), isMulti);
+        CellLayout cl = mCellLayoutBuilder.createCellLayout(board.getWidth(), board.getHeight(),
+                isMulti);
 
         // The views have to be sorted or the result can vary
         board.getIcons()
@@ -249,22 +223,6 @@
         }
     }
 
-    @Before
-    public void storePreviousValues() {
-        Context c = new ActivityContextWrapper(getApplicationContext());
-        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
-        mPrevNumColumns = dp.inv.numColumns;
-        mPrevNumRows = dp.inv.numRows;
-    }
-
-    @After
-    public void restorePreviousValues() {
-        Context c = new ActivityContextWrapper(getApplicationContext());
-        DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(c).getDeviceProfile(c).copy(c);
-        dp.inv.numColumns = mPrevNumColumns;
-        dp.inv.numRows = mPrevNumRows;
-    }
-
     private ReorderAlgorithmUnitTestCase generateRandomTestCase(
             RandomBoardGenerator boardGenerator) {
         ReorderAlgorithmUnitTestCase testCase = new ReorderAlgorithmUnitTestCase();
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt b/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
new file mode 100644
index 0000000..0bec1b2
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/ReorderPreviewAnimationTest.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.content.Context
+import android.util.ArrayMap
+import android.view.View
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.CellLayout
+import com.android.launcher3.Reorderable
+import com.android.launcher3.celllayout.ReorderPreviewAnimation.Companion.HINT_DURATION
+import com.android.launcher3.celllayout.ReorderPreviewAnimation.Companion.PREVIEW_DURATION
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.MultiTranslateDelegate
+import com.android.launcher3.util.MultiTranslateDelegate.INDEX_REORDER_BOUNCE_OFFSET
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+class Mock(context: Context) : Reorderable, View(context) {
+
+    init {
+        mLeft = 0
+        mRight = 100
+    }
+
+    private val translateDelegate = MultiTranslateDelegate(this)
+
+    private var scaleForReorderBounce = 1f
+    override fun getTranslateDelegate(): MultiTranslateDelegate {
+        return translateDelegate
+    }
+
+    override fun setReorderBounceScale(scale: Float) {
+        scaleForReorderBounce = scale
+    }
+
+    override fun getReorderBounceScale(): Float {
+        return scaleForReorderBounce
+    }
+
+    fun toAnimationValues(): AnimationValues {
+        return AnimationValues(
+            (translateDelegate.getTranslationX(INDEX_REORDER_BOUNCE_OFFSET).value * 100).toInt(),
+            (translateDelegate.getTranslationY(INDEX_REORDER_BOUNCE_OFFSET).value * 100).toInt(),
+            (scaleForReorderBounce * 100).toInt()
+        )
+    }
+}
+
+data class AnimationValues(val dx: Int, val dy: Int, val scale: Int)
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ReorderPreviewAnimationTest {
+
+    @JvmField @Rule var cellLayoutBuilder = UnitTestCellLayoutBuilderRule()
+
+    private val applicationContext =
+        ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+    /**
+     * @param animationTime the time of the animation we will check the state against.
+     * @param mode the mode either PREVIEW_DURATION or HINT_DURATION.
+     * @param valueToMatch the state of the animation we expect to see at animationTime.
+     * @param isAfterReverse if the animation is finish and we are returning to the beginning.
+     */
+    private fun testAnimationAtGivenProgress(
+        animationTime: Int,
+        mode: Int,
+        valueToMatch: AnimationValues
+    ) {
+        val view = Mock(applicationContext)
+        val cellLayout = cellLayoutBuilder.createCellLayout(100, 100, false)
+        val map = ArrayMap<Reorderable, ReorderPreviewAnimation<Mock>>()
+        val animation =
+            ReorderPreviewAnimation(
+                view,
+                mode,
+                3,
+                3,
+                1,
+                7,
+                1,
+                1,
+                CellLayout.REORDER_PREVIEW_MAGNITUDE,
+                cellLayout,
+                map
+            )
+        // Remove delay because it's randomly generated and it can slightly change the results.
+        animation.animator.startDelay = 0
+        animation.animator.currentPlayTime = animationTime.toLong()
+        val currentValue = view.toAnimationValues()
+        assert(currentValue == valueToMatch) {
+            "The value of the animation $currentValue at $animationTime time (milliseconds) doesn't match the given value $valueToMatch"
+        }
+    }
+
+    @Test
+    fun testAnimationModePreview() {
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION * 0,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 0, dy = 0, scale = 100)
+        )
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION / 2,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 2, dy = -5, scale = 98)
+        )
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION / 3,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 1, dy = -2, scale = 99)
+        )
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 5, dy = -10, scale = 96)
+        )
+
+        // MODE_PREVIEW oscillates and goes back to 0,0
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION * 2,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 0, dy = 0, scale = 100)
+        )
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION * 99,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 5, dy = -10, scale = 96)
+        )
+        testAnimationAtGivenProgress(
+            PREVIEW_DURATION * 98,
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 0, dy = 0, scale = 100)
+        )
+        testAnimationAtGivenProgress(
+            (PREVIEW_DURATION * 1.5).toInt(),
+            ReorderPreviewAnimation.MODE_PREVIEW,
+            AnimationValues(dx = 2, dy = -5, scale = 98)
+        )
+    }
+
+    @Test
+    fun testAnimationModeHint() {
+        testAnimationAtGivenProgress(
+            HINT_DURATION * 0,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = 0, dy = 0, scale = 100)
+        )
+        testAnimationAtGivenProgress(
+            HINT_DURATION,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -5, dy = 10, scale = 96)
+        )
+        testAnimationAtGivenProgress(
+            HINT_DURATION / 2,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -2, dy = 5, scale = 98)
+        )
+        testAnimationAtGivenProgress(
+            HINT_DURATION / 3,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -1, dy = 2, scale = 99)
+        )
+        testAnimationAtGivenProgress(
+            HINT_DURATION,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -5, dy = 10, scale = 96)
+        )
+
+        // After one cycle the animationValues should always be the top values and don't cycle.
+        testAnimationAtGivenProgress(
+            HINT_DURATION * 2,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -5, dy = 10, scale = 96)
+        )
+        testAnimationAtGivenProgress(
+            HINT_DURATION * 99,
+            ReorderPreviewAnimation.MODE_HINT,
+            AnimationValues(dx = -5, dy = 10, scale = 96)
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
index 8bdcd03..28a1325 100644
--- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
+++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
@@ -30,6 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.MultipageCellLayout;
 import com.android.launcher3.celllayout.board.CellLayoutBoard;
@@ -58,7 +59,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TaplReorderWidgetsTest extends AbstractLauncherUiTest {
+public class TaplReorderWidgetsTest extends AbstractLauncherUiTest<Launcher> {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -72,7 +73,7 @@
     @Before
     public void setup() throws Throwable {
         mWorkspaceBuilder = new TestWorkspaceBuilder(mTargetContext);
-        AbstractLauncherUiTest.initialize(this);
+        super.setUp();
     }
 
     @After
diff --git a/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt b/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
new file mode 100644
index 0000000..b63966d
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/UnitTestCellLayoutBuilderRule.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.content.Context
+import android.graphics.Point
+import android.view.View
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.CellLayout
+import com.android.launcher3.CellLayoutContainer
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.MultipageCellLayout
+import com.android.launcher3.util.ActivityContextWrapper
+import org.junit.rules.TestWatcher
+import org.junit.runner.Description
+
+/**
+ * Create CellLayouts to be used in Unit testing and make sure to set the DeviceProfile back to
+ * normal.
+ */
+class UnitTestCellLayoutBuilderRule : TestWatcher() {
+
+    private var prevNumColumns = 0
+    private var prevNumRows = 0
+
+    private val applicationContext =
+        ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+    private val container =
+        object : CellLayoutContainer {
+            override fun getCellLayoutId(cellLayout: CellLayout): Int = 0
+
+            override fun getCellLayoutIndex(cellLayout: CellLayout): Int = 0
+
+            override fun getPanelCount(): Int = 1
+
+            override fun getPageDescription(pageIndex: Int): String = ""
+        }
+
+    override fun starting(description: Description?) {
+        val dp = getDeviceProfile()
+        prevNumColumns = dp.inv.numColumns
+        prevNumRows = dp.inv.numRows
+    }
+
+    override fun finished(description: Description?) {
+        val dp = getDeviceProfile()
+        dp.inv.numColumns = prevNumColumns
+        dp.inv.numRows = prevNumRows
+    }
+
+    fun createCellLayout(width: Int, height: Int, isMulti: Boolean): CellLayout {
+        val dp = getDeviceProfile()
+        // modify the device profile.
+        dp.inv.numColumns = if (isMulti) width / 2 else width
+        dp.inv.numRows = height
+        dp.cellLayoutBorderSpacePx = Point(0, 0)
+        val cl =
+            if (isMulti) MultipageCellLayout(getWrappedContext(applicationContext, dp))
+            else CellLayout(getWrappedContext(applicationContext, dp), container)
+        // I put a very large number for width and height so that all the items can fit, it doesn't
+        // need to be exact, just bigger than the sum of cell border
+        cl.measure(
+            View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY),
+            View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.EXACTLY)
+        )
+        return cl
+    }
+
+    private fun getDeviceProfile(): DeviceProfile =
+        InvariantDeviceProfile.INSTANCE[applicationContext].getDeviceProfile(applicationContext)
+            .copy(applicationContext)
+
+    private fun getWrappedContext(context: Context, dp: DeviceProfile): Context {
+        return object : ActivityContextWrapper(context) {
+            override fun getDeviceProfile(): DeviceProfile {
+                return dp
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
index 770024f..ff46987 100644
--- a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
@@ -21,13 +21,20 @@
 
 /** Generates a random CellLayoutBoard. */
 open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerator(generator) {
+
+    companion object {
+        // This is the max number of widgets because we encode the widgets as letters A-Z and we
+        // already have some of those letter used by other things so 22 is a safe number
+        val MAX_NUMBER_OF_WIDGETS = 22
+    }
+
     /**
      * @param remainingEmptySpaces the maximum number of spaces we will fill with icons and widgets
      *   meaning that if the number is 100 we will try to fill the board with at most 100 spaces
      *   usually less than 100.
      * @return a randomly generated board filled with icons and widgets.
      */
-    open fun generateBoard(width: Int, height: Int, remainingEmptySpaces: Int): CellLayoutBoard? {
+    open fun generateBoard(width: Int, height: Int, remainingEmptySpaces: Int): CellLayoutBoard {
         val cellLayoutBoard = CellLayoutBoard(width, height)
         return fillBoard(cellLayoutBoard, Rect(0, 0, width, height), remainingEmptySpaces)
     }
@@ -39,17 +46,24 @@
     ): CellLayoutBoard {
         var remainingEmptySpaces = remainingEmptySpacesArg
         if (area.height() * area.width() <= 0) return board
-        val width = getRandom(1, area.width() - 1)
-        val height = getRandom(1, area.height() - 1)
+        val width = getRandom(1, area.width())
+        val height = getRandom(1, area.height())
         val x = area.left + getRandom(0, area.width() - width)
         val y = area.top + getRandom(0, area.height() - height)
         if (remainingEmptySpaces > 0) {
             remainingEmptySpaces -= width * height
-        } else if (board.widgets.size <= 22 && width * height > 1) {
+        }
+
+        if (board.widgets.size <= MAX_NUMBER_OF_WIDGETS && width * height > 1) {
             board.addWidget(x, y, width, height)
         } else {
             board.addIcon(x, y)
         }
+
+        if (remainingEmptySpaces < 0) {
+            // optimization, no need to keep going
+            return board
+        }
         fillBoard(board, Rect(area.left, area.top, area.right, y), remainingEmptySpaces)
         fillBoard(board, Rect(area.left, y, x, area.bottom), remainingEmptySpaces)
         fillBoard(board, Rect(x, y + height, area.right, area.bottom), remainingEmptySpaces)
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
new file mode 100644
index 0000000..a006fd7
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout.testgenerator
+
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.gridmigration.WorkspaceItem
+import java.util.Random
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * Generate a list of WorkspaceItem's for the given test case.
+ *
+ * @param repeatAfter a number after which we would repeat the same number of icons and widgets to
+ *   account for cases where the user have the same item multiple times.
+ */
+fun generateItemsForTest(
+    boards: List<CellLayoutBoard>,
+    repeatAfterRange: Point
+): List<WorkspaceItem> {
+    val id = AtomicInteger(0)
+    val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
+    // Repeat the same appWidgetProvider and intent to have repeating widgets and icons and test
+    // that case too
+    val getIntent = { i: Int -> "Intent ${(i + repeatAfterRange.x) % repeatAfterRange.y}" }
+    val getProvider = { i: Int ->
+        "com.test/test.Provider${(i + repeatAfterRange.x) % repeatAfterRange.y }"
+    }
+    val hotseatEntries =
+        (0 until boards[0].width).map {
+            WorkspaceItem(
+                x = it,
+                y = 0,
+                spanX = 1,
+                spanY = 1,
+                id = id.getAndAdd(1),
+                screenId = it,
+                title = "Hotseat ${id.get()}",
+                appWidgetId = -1,
+                appWidgetProvider = "Hotseat icons don't have a provider",
+                intent = getIntent(id.get()),
+                type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+                container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+            )
+        }
+    var widgetEntries =
+        boards
+            .flatMapIndexed { i, board -> board.widgets.map { Pair(i, it) } }
+            .map {
+                WorkspaceItem(
+                    x = it.second.cellX,
+                    y = it.second.cellY,
+                    spanX = it.second.spanX,
+                    spanY = it.second.spanY,
+                    id = id.getAndAdd(1),
+                    screenId = it.first,
+                    title = "Title Widget ${id.get()}",
+                    appWidgetId = widgetId.getAndAdd(-1),
+                    appWidgetProvider = getProvider(id.get()),
+                    intent = "Widgets don't have intent",
+                    type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
+                    container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+                )
+            }
+    widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
+    val iconEntries =
+        boards
+            .flatMapIndexed { i, board -> board.icons.map { Pair(i, it) } }
+            .map {
+                WorkspaceItem(
+                    x = it.second.coord.x,
+                    y = it.second.coord.y,
+                    spanX = 1,
+                    spanY = 1,
+                    id = id.getAndAdd(1),
+                    screenId = it.first,
+                    title = "Title Icon ${id.get()}",
+                    appWidgetId = -1,
+                    appWidgetProvider = "Icons don't have providers",
+                    intent = getIntent(id.get()),
+                    type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+                    container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+                )
+            }
+    return widgetEntries + hotseatEntries + iconEntries
+}
+
+data class GridMigrationUnitTestCase(
+    val boards: List<CellLayoutBoard>,
+    val destBoards: List<CellLayoutBoard>,
+    val srcSize: Point,
+    val targetSize: Point,
+    val seed: Long
+)
+
+class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
+    DeterministicRandomGenerator(generator) {
+
+    companion object {
+        const val MAX_BOARD_SIZE = 12
+        const val MAX_BOARD_COUNT = 10
+        const val SEED = 10342
+    }
+
+    private fun generateBoards(
+        boardGenerator: RandomBoardGenerator,
+        width: Int,
+        height: Int,
+        boardCount: Int
+    ): List<CellLayoutBoard> {
+        val boards = mutableListOf<CellLayoutBoard>()
+        for (i in 0 until boardCount) {
+            boards.add(
+                boardGenerator.generateBoard(
+                    width,
+                    height,
+                    boardGenerator.getRandom(0, width * height)
+                )
+            )
+        }
+        return boards
+    }
+
+    fun generateTestCase(isDestEmpty: Boolean): GridMigrationUnitTestCase {
+        val seed = generator.nextLong()
+        val randomBoardGenerator = RandomBoardGenerator(Random(seed))
+        val width = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+        val height = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+        val targetSize =
+            Point(
+                randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
+                randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+            )
+        val destBoards =
+            if (isDestEmpty) {
+                listOf()
+            } else {
+                generateBoards(
+                    boardGenerator = randomBoardGenerator,
+                    width = targetSize.x,
+                    height = targetSize.y,
+                    boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+                )
+            }
+        return GridMigrationUnitTestCase(
+            boards =
+                generateBoards(
+                    boardGenerator = randomBoardGenerator,
+                    width = width,
+                    height = height,
+                    boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+                ),
+            destBoards = destBoards,
+            srcSize = Point(width, height),
+            targetSize = targetSize,
+            seed = seed
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
index 8200c94..1500538 100644
--- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
@@ -15,9 +15,16 @@
  */
 package com.android.launcher3.compat;
 
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
+
+import static com.google.common.truth.Truth.assertThat;
+
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.text.TextUtils;
 
 import androidx.test.filters.LargeTest;
@@ -25,14 +32,18 @@
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.AllApps;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
+import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.ViewCaptureRule;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.UUID;
 
 
@@ -41,7 +52,15 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplPromiseIconUiTest extends AbstractLauncherUiTest {
+public class TaplPromiseIconUiTest extends AbstractLauncherUiTest<Launcher> {
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    public static final String PACKAGE_NAME = "test.promise.app";
+    public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
+    public static final String DUMMY_LABEL = "Aardwolf";
 
     private int mSessionId = -1;
 
@@ -55,18 +74,19 @@
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
         if (mSessionId > -1) {
             mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
         }
+        TestUtil.uninstallDummyApp();
     }
 
     /**
      * Create a session and return the id.
      */
-    private int createSession(String label, Bitmap icon) throws Throwable {
+    private int createSession(String packageName, String label, Bitmap icon) throws Throwable {
         SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
-        params.setAppPackageName("test.promise.app");
+        params.setAppPackageName(packageName);
         params.setAppLabel(label);
         params.setAppIcon(icon);
         params.setInstallReason(PackageManager.INSTALL_REASON_USER);
@@ -80,7 +100,8 @@
                 info != null && TextUtils.equals(info.title, appLabel);
 
         // Create and add test session
-        mSessionId = createSession(appLabel, Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
+        mSessionId = createSession(PACKAGE_NAME, appLabel,
+                Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
 
         // Verify promise icon is added
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
@@ -103,7 +124,7 @@
                 info != null && TextUtils.equals(info.title, appLabel);
 
         // Create and add test session without icon or label
-        mSessionId = createSession(null, null);
+        mSessionId = createSession(PACKAGE_NAME, null, null);
 
         // Sleep for duration of animation if a view was to be added + some buffer time.
         Thread.sleep(Launcher.NEW_APPS_PAGE_MOVE_DELAY + Launcher.NEW_APPS_ANIMATION_DELAY + 500);
@@ -112,4 +133,43 @@
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
                 launcher.getWorkspace().getFirstMatch(findPromiseApp) == null);
     }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    public void testPromiseIcon_addedArchivedApp() throws Throwable {
+        installDummyAppAndWaitForUIUpdate();
+        assertThat(mDevice.executeShellCommand(String.format("pm archive %s", DUMMY_PACKAGE)))
+                .isEqualTo("Success\n");
+
+        // Create and add test session
+        mSessionId = createSession(DUMMY_PACKAGE, /* label= */ "",
+                Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8));
+
+        // Verify promise icon is added to all apps view. The icon may not be added to the
+        // workspace even if there might be no icon present for archived app. But icon will
+        // always be in all apps view. In case an icon is not added, an exception would be thrown.
+        final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+
+        // Wait for the promise icon to be added.
+        waitForLauncherCondition(
+                DUMMY_PACKAGE + " app was not found on all apps after being archived",
+                launcher -> {
+                    try {
+                        allApps.getAppIcon(DUMMY_LABEL);
+                    } catch (Throwable t) {
+                        return false;
+                    }
+                    return true;
+                });
+
+        // Remove session
+        mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+        mSessionId = -1;
+    }
+
+    private void installDummyAppAndWaitForUIUpdate() throws IOException {
+        TestUtil.installDummyApp();
+        mLauncher.waitForModelQueueCleared();
+        mLauncher.waitForLauncherInitialized();
+    }
 }
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index e040367..d64d096 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -15,11 +15,14 @@
  */
 package com.android.launcher3.dragging;
 
-import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
 import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
+import static com.android.launcher3.util.TestConstants.AppNames.PHOTOS_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.STORE_APP_NAME;
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
+import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -30,6 +33,7 @@
 import android.platform.test.annotations.PlatinumTest;
 import android.util.Log;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.tapl.Folder;
 import com.android.launcher3.tapl.FolderIcon;
 import com.android.launcher3.tapl.HomeAllApps;
@@ -40,9 +44,8 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
 
-import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -55,13 +58,7 @@
  *    * Can drag an icon from AllApps into the workspace
  *    * Can drag an icon on the Workspace to other positions of the Workspace.
  */
-public class TaplDragTest extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplDragTest extends AbstractLauncherUiTest<Launcher> {
 
     /**
      * Adds two icons to the Workspace and combines them into a folder, then makes sure the icons
@@ -71,28 +68,28 @@
     @Test
     @PortraitLandscape
     @ScreenRecord
-    @Ignore // b/233075289
+    // Staging; will be promoted to presubmit if stable
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @PlatinumTest(focusArea = "launcher")
     public void testDragToFolder() {
         // TODO: add the use case to drag an icon to an existing folder. Currently it either fails
         // on tablets or phones due to difference in resolution.
         final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
-        final HomeAppIcon gmailIcon = createShortcutInCenterIfNotExist(GMAIL_APP_NAME);
+        final HomeAppIcon photosIcon = createShortcutInCenterIfNotExist(PHOTOS_APP_NAME);
 
-        FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
+        FolderIcon folderIcon = photosIcon.dragToIcon(playStoreIcon);
         Folder folder = folderIcon.open();
         folder.getAppIcon(STORE_APP_NAME);
-        folder.getAppIcon(GMAIL_APP_NAME);
+        folder.getAppIcon(PHOTOS_APP_NAME);
         Workspace workspace = folder.close();
 
         workspace.verifyWorkspaceAppIconIsGone(STORE_APP_NAME + " should be moved to a folder.",
                 STORE_APP_NAME);
-        workspace.verifyWorkspaceAppIconIsGone(GMAIL_APP_NAME + " should be moved to a folder.",
-                GMAIL_APP_NAME);
+        workspace.verifyWorkspaceAppIconIsGone(PHOTOS_APP_NAME + " should be moved to a folder.",
+                PHOTOS_APP_NAME);
 
         final HomeAppIcon mapIcon = createShortcutInCenterIfNotExist(MAPS_APP_NAME);
-        folderIcon = mapIcon.dragToIcon(folderIcon);
-        folder = folderIcon.open();
+        folder = mapIcon.dragToFolder(folderIcon);
         folder.getAppIcon(MAPS_APP_NAME);
         workspace = folder.close();
 
@@ -100,6 +97,21 @@
                 MAPS_APP_NAME);
     }
 
+    /**
+     * Adds two icons to the Workspace and combines them into a folder, then makes sure we are able
+     * to remove an icon from the folder and that the folder ceases to exist since it only has one
+     * icon left.
+     */
+    @Test
+    public void testDragOutOfFolder() {
+        final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
+        final HomeAppIcon photosIcon = createShortcutInCenterIfNotExist(PHOTOS_APP_NAME);
+        FolderIcon folderIcon = photosIcon.dragToIcon(playStoreIcon);
+        Folder folder = folderIcon.open();
+        folder.getAppIcon(STORE_APP_NAME).internalDragToWorkspace(false, false);
+        assertNotNull(mLauncher.getWorkspace().tryGetWorkspaceAppIcon(STORE_APP_NAME));
+        assertNotNull(mLauncher.getWorkspace().tryGetWorkspaceAppIcon(PHOTOS_APP_NAME));
+    }
 
     /** Drags a shortcut from a long press menu into the workspace.
      * 1. Open all apps and wait for load complete.
@@ -227,7 +239,7 @@
                 allApps.unfreeze();
             }
             // Reset the workspace for the next shortcut creation.
-            initialize(this, true);
+            reinitializeLauncherData(true);
             endTime = SystemClock.uptimeMillis();
             elapsedTime = endTime - startTime;
             Log.d("testDragAppIconToWorkspaceCellTime",
@@ -238,6 +250,11 @@
         final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(TEST_APP_NAME);
         for (Point target : targets) {
             startTime = SystemClock.uptimeMillis();
+            Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                    "TaplDragTest.java.testDragAppIconToMultipleWorkspaceCells: shortcut name: "
+                            + launcherTestAppIcon.getIconName()
+                            + " | target cell coordinates: (" + target.x + ", " + target.y
+                            + ") | start time: " + startTime);
             launcherTestAppIcon.dragToWorkspace(target.x, target.y);
             endTime = SystemClock.uptimeMillis();
             elapsedTime = endTime - startTime;
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
similarity index 90%
rename from tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
rename to tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 568fc9f..b7933c8 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemove.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -16,7 +16,7 @@
 package com.android.launcher3.dragging;
 
 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
+import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT;
 import static com.android.launcher3.util.TestConstants.AppNames.DUMMY_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
 import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
@@ -31,6 +31,7 @@
 import android.platform.test.annotations.PlatinumTest;
 import android.util.Log;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.tapl.HomeAppIcon;
 import com.android.launcher3.tapl.Workspace;
@@ -38,9 +39,9 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.TestStabilityRule;
 
-import org.junit.Before;
 import org.junit.Test;
 
 import java.io.IOException;
@@ -51,13 +52,7 @@
  * Test runs in Out of process (Oop) and In process (Ipc)
  * Test the behaviour of uninstalling and removing apps both from AllApps, Workspace and Hotseat.
  */
-public class TaplUninstallRemove extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplUninstallRemoveTest extends AbstractLauncherUiTest<Launcher> {
 
     /**
      * Deletes app both built-in and user-installed from the Workspace and makes sure it's no longer
@@ -120,6 +115,7 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/326130648
     public void testUninstallFromAllApps() throws Exception {
         installDummyAppAndWaitForUIUpdate();
         try {
@@ -137,6 +133,7 @@
      */
     @Test
     @PlatinumTest(focusArea = "launcher")
+    @ScreenRecordRule.ScreenRecord // b/319501259
     public void uninstallWorkspaceIcon() throws IOException {
         Point[] gridPositions = TestUtil.getCornersAndCenterPositions(mLauncher);
         StringBuilder sb = new StringBuilder();
@@ -155,6 +152,7 @@
                     0, Math.min(gridPositions.length, appNameCandidates.length));
 
             for (int i = 0; i < appNames.length; ++i) {
+                Log.d(UIOBJECT_STALE_ELEMENT, "creatingShortcut for: " + appNames[i]);
                 createShortcutIfNotExist(appNames[i], gridPositions[i]);
             }
 
@@ -166,11 +164,10 @@
             mLauncher.getWorkspace().verifyWorkspaceAppIconIsGone(
                     DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
 
-            if (!TestStabilityRule.isPresubmit()) { // b/315847371
-                Map<String, Point> finalPositions =
-                        mLauncher.getWorkspace().getWorkspaceIconsPositions();
-                assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
-            }
+            Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
+            Map<String, Point> finalPositions =
+                    mLauncher.getWorkspace().getWorkspaceIconsPositions();
+            assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
         } finally {
             TestUtil.uninstallDummyApp();
         }
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
new file mode 100644
index 0000000..da14425
--- /dev/null
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.folder
+
+import android.R
+import android.content.Context
+import android.os.Process
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.get
+import com.android.launcher3.icons.BaseIconFactory
+import com.android.launcher3.icons.FastBitmapDrawable
+import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.FlagOp
+import com.android.launcher3.util.LauncherLayoutBuilder
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.UserIconInfo
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for [PreviewItemManager] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PreviewItemManagerTest {
+
+    private lateinit var previewItemManager: PreviewItemManager
+    private lateinit var context: Context
+    private lateinit var folderItems: ArrayList<ItemInfo>
+    private lateinit var modelHelper: LauncherModelHelper
+    private lateinit var folderIcon: FolderIcon
+
+    @Before
+    fun setup() {
+        getInstrumentation().runOnMainSync {
+            folderIcon =
+                FolderIcon(ActivityContextWrapper(ApplicationProvider.getApplicationContext()))
+        }
+        context = getInstrumentation().targetContext
+        previewItemManager = PreviewItemManager(folderIcon)
+        modelHelper = LauncherModelHelper()
+        modelHelper
+            .setupDefaultLayoutProvider(
+                LauncherLayoutBuilder()
+                    .atWorkspace(0, 0, 1)
+                    .putFolder(R.string.copy)
+                    .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY)
+                    .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY2)
+                    .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY3)
+                    .addApp(LauncherModelHelper.TEST_PACKAGE, LauncherModelHelper.TEST_ACTIVITY4)
+                    .build()
+            )
+            .loadModelSync()
+        folderItems = modelHelper.bgDataModel.collections.valueAt(0).getContents()
+        folderIcon.mInfo = modelHelper.bgDataModel.collections.valueAt(0) as FolderInfo
+        folderIcon.mInfo.getContents().addAll(folderItems)
+
+        // Use getAppContents() to "cast" contents to WorkspaceItemInfo so we can set bitmaps
+        val folderApps = modelHelper.bgDataModel.collections.valueAt(0).getAppContents()
+        // Set first icon to be themed.
+        folderApps[0]
+            .bitmap
+            .setMonoIcon(
+                folderApps[0].bitmap.icon,
+                BaseIconFactory(
+                    context,
+                    context.resources.configuration.densityDpi,
+                    previewItemManager.mIconSize
+                )
+            )
+
+        // Set second icon to be non-themed.
+        folderApps[1]
+            .bitmap
+            .setMonoIcon(
+                null,
+                BaseIconFactory(
+                    context,
+                    context.resources.configuration.densityDpi,
+                    previewItemManager.mIconSize
+                )
+            )
+
+        // Set third icon to be themed with badge.
+        folderApps[2]
+            .bitmap
+            .setMonoIcon(
+                folderApps[2].bitmap.icon,
+                BaseIconFactory(
+                    context,
+                    context.resources.configuration.densityDpi,
+                    previewItemManager.mIconSize
+                )
+            )
+        folderApps[2].bitmap = folderApps[2].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
+
+        // Set fourth icon to be non-themed with badge.
+        folderApps[3].bitmap = folderApps[3].bitmap.withFlags(profileFlagOp(UserIconInfo.TYPE_WORK))
+        folderApps[3]
+            .bitmap
+            .setMonoIcon(
+                null,
+                BaseIconFactory(
+                    context,
+                    context.resources.configuration.densityDpi,
+                    previewItemManager.mIconSize
+                )
+            )
+    }
+    @After
+    @Throws(Exception::class)
+    fun tearDown() {
+        modelHelper.destroy()
+    }
+
+    @Test
+    fun checkThemedIconWithThemingOn_iconShouldBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, true)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[0])
+
+        assert((drawingParams.drawable as FastBitmapDrawable).isThemed)
+    }
+
+    @Test
+    fun checkThemedIconWithThemingOff_iconShouldNotBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, false)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[0])
+
+        assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+    }
+
+    @Test
+    fun checkUnthemedIconWithThemingOn_iconShouldNotBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, true)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[1])
+
+        assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+    }
+
+    @Test
+    fun checkUnthemedIconWithThemingOff_iconShouldNotBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, false)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[1])
+
+        assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+    }
+
+    @Test
+    fun checkThemedIconWithBadgeWithThemingOn_iconAndBadgeShouldBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, true)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[2])
+
+        assert((drawingParams.drawable as FastBitmapDrawable).isThemed)
+        assert(
+            ((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+        )
+    }
+
+    @Test
+    fun checkUnthemedIconWithBadgeWithThemingOn_badgeShouldBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, true)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[3])
+
+        assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+        assert(
+            ((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+        )
+    }
+
+    @Test
+    fun checkUnthemedIconWithBadgeWithThemingOff_iconAndBadgeShouldNotBeThemed() {
+        get(context).put(LauncherPrefs.THEMED_ICONS, false)
+        val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
+
+        previewItemManager.setDrawable(drawingParams, folderItems[3])
+
+        assert(!(drawingParams.drawable as FastBitmapDrawable).isThemed)
+        assert(
+            !((drawingParams.drawable as FastBitmapDrawable).badge as UserBadgeDrawable).mIsThemed
+        )
+    }
+
+    private fun profileFlagOp(type: Int) =
+        UserIconInfo(Process.myUserHandle(), type).applyBitmapInfoFlags(FlagOp.NO_OP)
+}
diff --git a/tests/src/com/android/launcher3/model/AsyncBindingTest.kt b/tests/src/com/android/launcher3/model/AsyncBindingTest.kt
new file mode 100644
index 0000000..af367a8
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/AsyncBindingTest.kt
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.os.Looper
+import android.platform.test.flag.junit.SetFlagsRule
+import android.util.Pair
+import android.util.SparseArray
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags
+import com.android.launcher3.model.BgDataModel.Callbacks
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.IntArray
+import com.android.launcher3.util.IntSet
+import com.android.launcher3.util.ItemInflater
+import com.android.launcher3.util.LauncherLayoutBuilder
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
+import com.android.launcher3.util.RunnableList
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.Spy
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argThat
+import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.isNull
+import org.mockito.kotlin.never
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** Tests to verify async binding of model views */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AsyncBindingTest {
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    @Spy private var callbacks = MyCallbacks()
+    @Mock private lateinit var itemInflater: ItemInflater<*>
+
+    private val inflationLooper = SparseArray<Looper>()
+
+    private lateinit var modelHelper: LauncherModelHelper
+
+    @Before
+    fun setUp() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+        MockitoAnnotations.initMocks(this)
+        modelHelper = LauncherModelHelper()
+
+        doAnswer { i ->
+                inflationLooper[(i.arguments[0] as ItemInfo).id] = Looper.myLooper()
+                View(modelHelper.sandboxContext)
+            }
+            .whenever(itemInflater)
+            .inflateItem(any(), any(), isNull())
+
+        // Set up the workspace with 3 pages of apps
+        modelHelper.setupDefaultLayoutProvider(
+            LauncherLayoutBuilder()
+                .atWorkspace(0, 1, 0)
+                .putApp(TEST_PACKAGE, TEST_PACKAGE)
+                .atWorkspace(1, 1, 0)
+                .putApp(TEST_PACKAGE, TEST_PACKAGE)
+                .atWorkspace(0, 1, 1)
+                .putApp(TEST_PACKAGE, TEST_PACKAGE)
+                .atWorkspace(1, 1, 1)
+                .putApp(TEST_PACKAGE, TEST_PACKAGE)
+                .atWorkspace(0, 1, 2)
+                .putApp(TEST_PACKAGE, TEST_PACKAGE)
+        )
+    }
+
+    @After
+    fun tearDown() {
+        modelHelper.destroy()
+    }
+
+    @Test
+    fun test_bind_normally_without_itemInflater() {
+        MAIN_EXECUTOR.execute { modelHelper.model.addCallbacksAndLoad(callbacks) }
+        waitForLoaderAndTempMainThread()
+
+        verify(callbacks, never()).bindInflatedItems(any())
+        verify(callbacks, atLeastOnce()).bindItems(any(), any())
+    }
+
+    @Test
+    fun test_bind_inflates_item_on_background() {
+        callbacks.inflater = itemInflater
+        MAIN_EXECUTOR.execute { modelHelper.model.addCallbacksAndLoad(callbacks) }
+        waitForLoaderAndTempMainThread()
+
+        verify(callbacks, never()).bindItems(any(), any())
+        verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 2 })
+
+        // Verify remaining items are bound using pendingTasks
+        reset(callbacks)
+        MAIN_EXECUTOR.submit(callbacks.pendingTasks!!::executeAllAndDestroy).get()
+        verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 3 })
+
+        // Verify that all items were inflated on the background thread
+        assertEquals(5, inflationLooper.size())
+        for (i in 0..4) assertEquals(MODEL_EXECUTOR.looper, inflationLooper.valueAt(i))
+    }
+
+    @Test
+    fun test_bind_sync_partially_inflates_on_background() {
+        modelHelper.loadModelSync()
+        assertTrue(modelHelper.model.isModelLoaded)
+        callbacks.inflater = itemInflater
+
+        val firstPageBindIds = IntSet()
+
+        MAIN_EXECUTOR.submit {
+                modelHelper.model.addCallbacksAndLoad(callbacks)
+                verify(callbacks, never()).bindItems(any(), any())
+                verify(callbacks, times(1))
+                    .bindInflatedItems(
+                        argThat { t ->
+                            t.forEach { firstPageBindIds.add(it.first.id) }
+                            t.size == 2
+                        }
+                    )
+
+                // Verify that onInitialBindComplete is called and the binding is not yet complete
+                assertFalse(callbacks.onCompleteSignal!!.isDestroyed)
+            }
+            .get()
+
+        waitForLoaderAndTempMainThread()
+        assertTrue(callbacks.onCompleteSignal!!.isDestroyed)
+
+        // Verify that firstPageBindIds are loaded on the main thread and remaining
+        // on the background thread.
+        assertEquals(5, inflationLooper.size())
+        for (i in 0..4) {
+            if (firstPageBindIds.contains(inflationLooper.keyAt(i)))
+                assertEquals(MAIN_EXECUTOR.looper, inflationLooper.valueAt(i))
+            else assertEquals(MODEL_EXECUTOR.looper, inflationLooper.valueAt(i))
+        }
+
+        MAIN_EXECUTOR.submit {
+                reset(callbacks)
+                callbacks.pendingTasks!!.executeAllAndDestroy()
+                // Verify remaining 3 times are bound using pending tasks
+                verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 3 })
+            }
+            .get()
+    }
+
+    private fun waitForLoaderAndTempMainThread() {
+        MAIN_EXECUTOR.submit {}.get()
+        MODEL_EXECUTOR.submit {}.get()
+        MAIN_EXECUTOR.submit {}.get()
+    }
+
+    class MyCallbacks : Callbacks {
+
+        var inflater: ItemInflater<*>? = null
+        var pendingTasks: RunnableList? = null
+        var onCompleteSignal: RunnableList? = null
+
+        override fun bindItems(shortcuts: MutableList<ItemInfo>, forceAnimateIcons: Boolean) {}
+
+        override fun bindInflatedItems(items: MutableList<Pair<ItemInfo, View>>) {}
+
+        override fun getPagesToBindSynchronously(orderedScreenIds: IntArray?) = IntSet.wrap(0)
+
+        override fun onInitialBindComplete(
+            boundPages: IntSet,
+            pendingTasks: RunnableList,
+            onCompleteSignal: RunnableList,
+            workspaceItemCount: Int,
+            isBindSync: Boolean
+        ) {
+            this.pendingTasks = pendingTasks
+            this.onCompleteSignal = onCompleteSignal
+        }
+
+        override fun getItemInflater() = inflater
+    }
+}
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index f771052..d3a6355 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -8,6 +8,8 @@
 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
 import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
 import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -26,10 +28,13 @@
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.LauncherModelHelper;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.rule.TestStabilityRule;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 
 import java.util.Arrays;
@@ -43,6 +48,9 @@
 @RunWith(AndroidJUnit4.class)
 public class CacheDataUpdatedTaskTest {
 
+    @Rule(order = 0)
+    public TestRule testStabilityRule = new TestStabilityRule();
+
     private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
     private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
 
@@ -90,6 +98,7 @@
     }
 
     @Test
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
     public void testCacheUpdate_update_apps() {
         // Run on model executor so that no other task runs in the middle.
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
@@ -120,6 +129,7 @@
     }
 
     @Test
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
     public void testSessionUpdate_updates_pending_apps() {
         // Run on model executor so that no other task runs in the middle.
         runOnExecutorSync(MODEL_EXECUTOR, () -> {
@@ -150,6 +160,6 @@
     }
 
     private List<WorkspaceItemInfo> allItems() {
-        return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).contents;
+        return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getAppContents();
     }
 }
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 2b89321..10785f7 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -87,7 +87,7 @@
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
-        assertEquals(3, ((FolderInfo) info).contents.size());
+        assertEquals(3, ((FolderInfo) info).getContents().size());
     }
 
     @Test
@@ -102,7 +102,7 @@
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
-        assertEquals(3, ((FolderInfo) info).contents.size());
+        assertEquals(3, ((FolderInfo) info).getContents().size());
         assertEquals("CustomFolder", info.title.toString());
     }
 
@@ -154,11 +154,11 @@
         // Verify folder
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         FolderInfo info = (FolderInfo) mModelHelper.getBgDataModel().workspaceItems.get(0);
-        assertEquals(3, info.contents.size());
+        assertEquals(3, info.getContents().size());
 
         // Verify last icon
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
-                info.contents.get(info.contents.size() - 1).itemType);
+                info.getContents().get(info.getContents().size() - 1).itemType);
     }
 
     private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 60a4d2d..2e209a4 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -24,11 +24,13 @@
 import com.android.launcher3.util.LauncherModelHelper
 import com.android.launcher3.util.LauncherModelHelper.*
 import com.android.launcher3.util.TestUtil
+import com.android.launcher3.util.rule.TestStabilityRule
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import java.util.concurrent.CountDownLatch
 import org.junit.After
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -56,6 +58,8 @@
             TEST_ACTIVITY14
         )
 
+    @get:Rule(order = 0) val testStabilityRule = TestStabilityRule()
+
     @Before
     fun setUp() {
         modelHelper = LauncherModelHelper()
@@ -87,6 +91,9 @@
 
     @Test
     @Throws(Exception::class)
+    @TestStabilityRule.Stability(
+        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+    ) // b/319923578
     fun folderLoadedWithHighRes_max_3x3() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(3, 3, 3, 3)
@@ -100,6 +107,9 @@
 
     @Test
     @Throws(Exception::class)
+    @TestStabilityRule.Stability(
+        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+    ) // b/319923578
     fun folderLoadedWithHighRes_max_4x4() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(4, 4, 4, 4)
@@ -113,6 +123,10 @@
 
     @Test
     @Throws(Exception::class)
+    // Stress tests are long. We permanently demote them from presubmit to match the presubmit SLO.
+    @TestStabilityRule.Stability(
+        flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT
+    ) // b/319923578
     fun folderLoadedWithHighRes_differentFolderConfigurations() {
         val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
         idp.numFolderColumns = intArrayOf(4, 3, 4, 4)
@@ -151,11 +165,11 @@
         // Reload again with correct icon state
         app.model.forceReload()
         modelHelper.loadModelSync()
-        val folders = modelHelper.getBgDataModel().folders
+        val collections = modelHelper.getBgDataModel().collections
 
-        assertThat(folders.size()).isEqualTo(1)
-        assertThat(folders.valueAt(0).contents.size).isEqualTo(itemCount)
-        return folders.valueAt(0).contents
+        assertThat(collections.size()).isEqualTo(1)
+        assertThat(collections.valueAt(0).getAppContents().size).isEqualTo(itemCount)
+        return collections.valueAt(0).getAppContents()
     }
 
     private fun verifyHighRes(items: ArrayList<WorkspaceItemInfo>, vararg indices: Int) {
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
new file mode 100644
index 0000000..15222a4
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags
+import com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE
+import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.util.rule.TestToPhoneFileCopier
+import com.android.launcher3.util.rule.setFlags
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private val phoneContext = InstrumentationRegistry.getInstrumentation().targetContext
+
+data class EntryData(val x: Int, val y: Int, val spanX: Int, val spanY: Int, val rank: Int)
+
+/**
+ * Holds the data needed to run a test in GridMigrationTest, usually we would have a src
+ * GridMigrationData and a dst GridMigrationData meaning the data after a migration has occurred.
+ * This class holds a gridState, which is the size of the grid like 5x5 (among other things). a
+ * dbHelper which contains the readable database and writable database used to migrate the
+ * databases.
+ *
+ * You can also get all the entries defined in the dbHelper database.
+ */
+class GridMigrationData(dbFileName: String?, val gridState: DeviceGridState) {
+
+    val dbHelper: DatabaseHelper =
+        DatabaseHelper(
+            phoneContext,
+            dbFileName,
+            { UserCache.INSTANCE.get(phoneContext).getSerialNumberForUser(it) },
+            {}
+        )
+
+    fun readEntries(): List<GridSizeMigrationUtil.DbEntry> =
+        GridSizeMigrationUtil.readAllEntries(dbHelper.readableDatabase, TABLE_NAME, phoneContext)
+}
+
+/**
+ * Test the migration of a database from one size to another. It reads a database from the test
+ * assets, uploads it into the phone and migrates the database to a database in memory which is
+ * later compared against a database in the test assets to make sure they are identical.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GridMigrationTest {
+    private val DB_FILE = "test_launcher.db"
+
+    @JvmField
+    @Rule
+    val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+    // Copying the src db for all tests.
+    @JvmField
+    @Rule
+    val fileCopier =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/$DB_FILE",
+            dest = "databases/$DB_FILE",
+            removeOnFinish = true
+        )
+
+    @Before
+    fun setup() {
+        setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+    }
+
+    private fun migrate(src: GridMigrationData, dst: GridMigrationData) {
+        GridSizeMigrationUtil.migrateGridIfNeeded(
+            phoneContext,
+            src.gridState,
+            dst.gridState,
+            dst.dbHelper,
+            src.dbHelper.readableDatabase
+        )
+    }
+
+    /**
+     * Makes sure that none of the items overlaps on the result, i.e. no widget or icons share the
+     * same space in the db.
+     */
+    private fun validateDb(data: GridMigrationData) {
+        // The array size is just a big enough number to fit all the number of workspaces
+        val boards = Array(100) { CellLayoutBoard(data.gridState.columns, data.gridState.rows) }
+        data.readEntries().forEach {
+            val cellLayoutBoard = boards[it.screenId]
+            assert(cellLayoutBoard.isEmpty(it.cellX, it.cellY, it.spanX, it.spanY)) {
+                "Db has overlapping items"
+            }
+            cellLayoutBoard.addWidget(it.cellX, it.cellY, it.spanX, it.spanY)
+        }
+    }
+
+    private fun compare(dst: GridMigrationData, target: GridMigrationData) {
+        val sort = compareBy<GridSizeMigrationUtil.DbEntry>({ it.cellX }, { it.cellY })
+        val mapF = { it: GridSizeMigrationUtil.DbEntry ->
+            EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank)
+        }
+        val entriesDst = dst.readEntries().sortedWith(sort).map(mapF)
+        val entriesTarget = target.readEntries().sortedWith(sort).map(mapF)
+
+        assert(entriesDst == entriesTarget) {
+            "The elements on the dst database is not the same as in the target"
+        }
+    }
+
+    /**
+     * Migrate src into dst and compare to target. This method validates 3 things:
+     * 1. dst has the same number of items as src after the migration, meaning, none of the items
+     *    were removed during the migration.
+     * 2. dst is valid, meaning that none of the items overlap with each other.
+     * 3. dst is equal to target to ensure we don't unintentionally change the migration logic.
+     */
+    private fun runTest(src: GridMigrationData, dst: GridMigrationData, target: GridMigrationData) {
+        migrate(src, dst)
+        assert(src.readEntries().size == dst.readEntries().size) {
+            "Source db and destination db do not contain the same number of elements"
+        }
+        validateDb(dst)
+        compare(dst, target)
+    }
+
+    @JvmField
+    @Rule
+    val result5x5to3x3 =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/result5x5to3x3.db",
+            dest = "databases/result5x5to3x3.db",
+            removeOnFinish = true
+        )
+
+    @Test
+    fun `5x5 to 3x3`() =
+        runTest(
+            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            dst =
+                GridMigrationData(
+                    null, // in memory db, to download a new db change null for the filename of the
+                    // db name to store it. Do not use existing names.
+                    DeviceGridState(3, 3, 3, TYPE_PHONE, "")
+                ),
+            target =
+                GridMigrationData("result5x5to3x3.db", DeviceGridState(3, 3, 3, TYPE_PHONE, ""))
+        )
+
+    @JvmField
+    @Rule
+    val result5x5to4x7 =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/result5x5to4x7.db",
+            dest = "databases/result5x5to4x7.db",
+            removeOnFinish = true
+        )
+
+    @Test
+    fun `5x5 to 4x7`() =
+        runTest(
+            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            dst =
+                GridMigrationData(
+                    null, // in memory db, to download a new db change null for the filename of the
+                    // db name to store it. Do not use existing names.
+                    DeviceGridState(4, 7, 4, TYPE_PHONE, "")
+                ),
+            target =
+                GridMigrationData("result5x5to4x7.db", DeviceGridState(4, 7, 4, TYPE_PHONE, ""))
+        )
+
+    @JvmField
+    @Rule
+    val result5x5to5x8 =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/result5x5to5x8.db",
+            dest = "databases/result5x5to5x8.db",
+            removeOnFinish = true
+        )
+
+    @Test
+    fun `5x5 to 5x8`() =
+        runTest(
+            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            dst =
+                GridMigrationData(
+                    null, // in memory db, to download a new db change null for the filename of the
+                    // db name to store it. Do not use existing names.
+                    DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+                ),
+            target =
+                GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, ""))
+        )
+
+    @JvmField
+    @Rule
+    val flaggedResult5x5to5x8 =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/flagged_result5x5to5x8.db",
+            dest = "databases/flagged_result5x5to5x8.db",
+            removeOnFinish = true
+        )
+
+    @Test
+    fun `flagged 5x5 to 5x8`() {
+        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+        runTest(
+            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            dst =
+                GridMigrationData(
+                    null, // in memory db, to download a new db change null for the filename of the
+                    // db name to store it. Do not use existing names.
+                    DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+                ),
+            target =
+                GridMigrationData(
+                    "flagged_result5x5to5x8.db",
+                    DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+                )
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 04735f2..761f06d 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -28,7 +28,6 @@
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
 import com.android.launcher3.LauncherSettings.Favorites.*
-import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.model.GridSizeMigrationUtil.DbReader
 import com.android.launcher3.pm.UserCache
 import com.android.launcher3.provider.LauncherDbUtils
@@ -98,10 +97,7 @@
         modelHelper.destroy()
     }
 
-    /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
-     * needed anymore
-     */
+    /** Old migration logic, should be modified once is not needed anymore */
     @Test
     @Throws(Exception::class)
     fun testMigration() {
@@ -208,10 +204,7 @@
         assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2))
     }
 
-    /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
-     * needed anymore
-     */
+    /** Old migration logic, should be modified once is not needed anymore */
     @Test
     @Throws(Exception::class)
     fun testMigrationBackAndForth() {
@@ -606,68 +599,6 @@
     }
 
     /**
-     * Migrating from a smaller grid to a large one should keep the pages if the column difference
-     * is less than 2
-     */
-    @Test
-    @Throws(Exception::class)
-    fun migrateFromSmallerGridSmallDifference() {
-        enableNewMigrationLogic("4,4")
-
-        // Setup src grid
-        addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE)
-
-        idp.numDatabaseHotseatIcons = 4
-        idp.numColumns = 6
-        idp.numRows = 5
-
-        val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
-        val destReader = DbReader(db, TABLE_NAME, context, validPackages)
-        GridSizeMigrationUtil.migrate(
-            dbHelper,
-            srcReader,
-            destReader,
-            idp.numDatabaseHotseatIcons,
-            Point(idp.numColumns, idp.numRows),
-            DeviceGridState(context),
-            DeviceGridState(idp)
-        )
-
-        // Get workspace items
-        val c =
-            db.query(
-                TABLE_NAME,
-                arrayOf(INTENT, SCREEN),
-                "container=$CONTAINER_DESKTOP",
-                null,
-                null,
-                null,
-                null
-            )
-                ?: throw IllegalStateException()
-        val intentIndex = c.getColumnIndex(INTENT)
-        val screenIndex = c.getColumnIndex(SCREEN)
-
-        // Get in which screen the icon is
-        val locMap = HashMap<String?, Int>()
-        while (c.moveToNext()) {
-            locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
-                c.getInt(screenIndex)
-        }
-        c.close()
-        assertThat(locMap.size).isEqualTo(5)
-        assertThat(locMap[testPackage1]).isEqualTo(0)
-        assertThat(locMap[testPackage2]).isEqualTo(0)
-        assertThat(locMap[testPackage3]).isEqualTo(1)
-        assertThat(locMap[testPackage4]).isEqualTo(1)
-        assertThat(locMap[testPackage5]).isEqualTo(2)
-    }
-
-    /**
      * Migrating from a smaller grid to a large one should reflow the pages if the column difference
      * is more than 2
      */
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 389ec5c..56ac960 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -101,7 +101,7 @@
         });
 
         UserManagerState ums = new UserManagerState();
-        mLoaderCursor = new LoaderCursor(mCursor, mApp, ums);
+        mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, null);
         ums.allUsers.put(0, Process.myUserHandle());
     }
 
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index def27b8..5731e2a 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -1,11 +1,10 @@
 package com.android.launcher3.model
 
-import android.content.Context
+import android.appwidget.AppWidgetManager
 import android.os.UserHandle
 import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.Flags
 import com.android.launcher3.InvariantDeviceProfile
 import com.android.launcher3.LauncherAppState
@@ -15,17 +14,20 @@
 import com.android.launcher3.icons.cache.CachingLogic
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
 import com.android.launcher3.pm.UserCache
+import com.android.launcher3.ui.TestViewHelpers
 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.UserIconInfo
-import com.android.launcher3.util.rule.StaticMockitoRule
 import com.google.common.truth.Truth
 import java.util.concurrent.CountDownLatch
+import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.times
@@ -33,16 +35,18 @@
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 import org.mockito.Spy
+import org.mockito.kotlin.doReturn
 
 private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class LoaderTaskTest {
+    private var context = SandboxModelContext()
     @Mock private lateinit var app: LauncherAppState
     @Mock private lateinit var bgAllAppsList: AllAppsList
     @Mock private lateinit var modelDelegate: ModelDelegate
-    @Mock private lateinit var launcherBinder: LauncherBinder
+    @Mock private lateinit var launcherBinder: BaseLauncherBinder
     @Mock private lateinit var launcherModel: LauncherModel
     @Mock private lateinit var transaction: LoaderTransaction
     @Mock private lateinit var iconCache: IconCache
@@ -52,21 +56,24 @@
 
     @Spy private var userManagerState: UserManagerState? = UserManagerState()
 
-    @get:Rule(order = 0) val staticMockitoRule = StaticMockitoRule(UserCache::class.java)
-    @get:Rule(order = 1)
-    val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
+    @get:Rule val setFlagsRule = SetFlagsRule().apply { initAllFlagsToReleaseConfigDefault() }
 
     @Before
     fun setup() {
-        val context = InstrumentationRegistry.getInstrumentation().targetContext
+        MockitoAnnotations.initMocks(this)
+
         val idp =
-            InvariantDeviceProfile.INSTANCE[context].apply {
+            InvariantDeviceProfile().apply {
                 numRows = 5
                 numColumns = 6
                 numDatabaseHotseatIcons = 5
             }
+        context.putObject(InvariantDeviceProfile.INSTANCE, idp)
+        context.putObject(LauncherAppState.INSTANCE, app)
 
-        MockitoAnnotations.initMocks(this)
+        doReturn(TestViewHelpers.findWidgetProvider(false))
+            .`when`(context.spyService(AppWidgetManager::class.java))
+            .getAppWidgetInfo(anyInt())
         `when`(app.context).thenReturn(context)
         `when`(app.model).thenReturn(launcherModel)
         `when`(launcherModel.beginLoader(any(LoaderTask::class.java))).thenReturn(transaction)
@@ -77,17 +84,26 @@
         `when`(launcherBinder.newIdleLock(any(LoaderTask::class.java))).thenReturn(idleLock)
         `when`(idleLock.awaitLocked(1000)).thenReturn(false)
         `when`(iconCache.updateHandler).thenReturn(iconCacheUpdateHandler)
-        `when`(UserCache.getInstance(any(Context::class.java))).thenReturn(userCache)
+        context.putObject(UserCache.INSTANCE, userCache)
+    }
+
+    @After
+    fun tearDown() {
+        context.onDestroy()
     }
 
     @Test
     fun loadsDataProperly() =
         with(BgDataModel()) {
+            val MAIN_HANDLE = UserHandle.of(0)
+            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)
                 .runSyncOnBackgroundThread()
             Truth.assertThat(workspaceItems.size).isAtLeast(25)
             Truth.assertThat(appWidgets.size).isAtLeast(7)
-            Truth.assertThat(folders.size()).isAtLeast(8)
+            Truth.assertThat(collections.size()).isAtLeast(8)
             Truth.assertThat(itemsIdMap.size()).isAtLeast(40)
         }
 
diff --git a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
index 3dfd6b4..b140f2e 100644
--- a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
+++ b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
@@ -73,6 +73,10 @@
         TestUtil.uninstallDummyApp();
     }
 
+    private ModelLauncherCallbacks getCallbacks() {
+        return mModelHelper.getModel().newModelCallbacks();
+    }
+
     @Test
     public void testTwoCallbacks_loadedTogether() throws Exception {
         setupWorkspacePages(3);
@@ -127,14 +131,14 @@
 
         // Install package 1
         TestUtil.installDummyApp();
-        mModelHelper.getModel().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+        getCallbacks().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
         waitForLoaderAndTempMainThread();
         assertTrue(cb1.allApps().contains(TestUtil.DUMMY_PACKAGE));
         assertTrue(cb2.allApps().contains(TestUtil.DUMMY_PACKAGE));
 
         // Uninstall package 2
         TestUtil.uninstallDummyApp();
-        mModelHelper.getModel().onPackageRemoved(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+        getCallbacks().onPackageRemoved(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
         waitForLoaderAndTempMainThread();
         assertFalse(cb1.allApps().contains(TestUtil.DUMMY_PACKAGE));
         assertFalse(cb2.allApps().contains(TestUtil.DUMMY_PACKAGE));
@@ -142,7 +146,7 @@
         // Unregister a callback and verify updates no longer received
         Executors.MAIN_EXECUTOR.execute(() -> mModelHelper.getModel().removeCallbacks(cb2));
         TestUtil.installDummyApp();
-        mModelHelper.getModel().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
+        getCallbacks().onPackageAdded(TestUtil.DUMMY_PACKAGE, Process.myUserHandle());
         waitForLoaderAndTempMainThread();
 
         // cb2 didn't get the update
@@ -183,7 +187,7 @@
 
         @Override
         public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
-                int workspaceItemCount, boolean isBindSync) {
+                RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
             mPageBoundSync = boundPages;
             mPendingTasks = pendingTasks;
         }
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
new file mode 100644
index 0000000..c2e73fc
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model
+
+import android.appwidget.AppWidgetProviderInfo
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.content.pm.ShortcutInfo
+import android.os.UserHandle
+import android.util.LongSparseArray
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.PROFILE_DELETED
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.UserIconInfo
+import com.android.launcher3.widget.WidgetInflater
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+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.kotlin.any
+import org.mockito.kotlin.anyOrNull
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+class WorkspaceItemProcessorTest {
+
+    @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
+    @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
+    @Mock private lateinit var mockBgDataModel: BgDataModel
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var mockAppState: LauncherAppState
+    @Mock private lateinit var mockPmHelper: PackageManagerHelper
+    @Mock private lateinit var mockLauncherApps: LauncherApps
+    @Mock private lateinit var mockCursor: LoaderCursor
+    @Mock private lateinit var mockUserCache: UserCache
+    @Mock private lateinit var mockUserManagerState: UserManagerState
+    @Mock private lateinit var mockWidgetInflater: WidgetInflater
+
+    private lateinit var intent: Intent
+    private lateinit var userHandle: UserHandle
+    private lateinit var iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>
+    private lateinit var componentName: ComponentName
+    private lateinit var unlockedUsersArray: LongSparseArray<Boolean>
+    private lateinit var keyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo>
+    private lateinit var installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>
+    private lateinit var allDeepShortcuts: MutableList<ShortcutInfo>
+
+    private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
+
+    @Before
+    fun setup() {
+        userHandle = UserHandle(0)
+        mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
+        iconRequestInfos = mutableListOf(mockIconRequestInfo)
+        mockWorkspaceInfo = mock<WorkspaceItemInfo>()
+        mockBgDataModel = mock<BgDataModel>()
+        componentName = ComponentName("package", "class")
+        unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+        intent =
+            Intent().apply {
+                component = componentName
+                `package` = "pkg"
+                putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
+            }
+        mockContext =
+            mock<Context>().apply {
+                whenever(packageManager).thenReturn(mock())
+                whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
+            }
+        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(componentName.packageName, userHandle))
+                    .thenReturn(intent)
+            }
+        mockLauncherApps =
+            mock<LauncherApps>().apply {
+                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(true)
+            }
+        mockCursor =
+            mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
+                user = userHandle
+                itemType = ITEM_TYPE_APPLICATION
+                id = 1
+                restoreFlag = 1
+                serialNumber = 101
+                whenever(parseIntent()).thenReturn(intent)
+                whenever(markRestored()).doAnswer { restoreFlag = 0 }
+                whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
+                whenever(getAppShortcutInfo(any(), any(), any(), any()))
+                    .thenReturn(mockWorkspaceInfo)
+                whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
+            }
+        mockUserCache =
+            mock<UserCache>().apply {
+                val userIconInfo =
+                    mock<UserIconInfo>().apply() { whenever(isPrivate).thenReturn(false) }
+                whenever(getUserInfo(any())).thenReturn(userIconInfo)
+            }
+
+        mockUserManagerState = mock<UserManagerState>()
+        mockWidgetInflater = mock<WidgetInflater>()
+        keyToPinnedShortcutsMap = mutableMapOf()
+        installingPkgs = hashMapOf()
+        allDeepShortcuts = mutableListOf()
+    }
+
+    /**
+     * Helper to create WorkspaceItemProcessor with defaults. WorkspaceItemProcessor has a lot of
+     * dependencies, so this method can be used to inject concrete arguments while keeping the rest
+     * as mocks/defaults, or to recreate it after modifying the default vars.
+     */
+    private fun createWorkspaceItemProcessorUnderTest(
+        cursor: LoaderCursor = mockCursor,
+        memoryLogger: LoaderMemoryLogger? = null,
+        userCache: UserCache = mockUserCache,
+        userManagerState: UserManagerState = mockUserManagerState,
+        launcherApps: LauncherApps = mockLauncherApps,
+        shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = keyToPinnedShortcutsMap,
+        app: LauncherAppState = mockAppState,
+        bgDataModel: BgDataModel = mockBgDataModel,
+        widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mutableMapOf(),
+        widgetInflater: WidgetInflater = mockWidgetInflater,
+        pmHelper: PackageManagerHelper = mockPmHelper,
+        iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf(),
+        isSdCardReady: Boolean = false,
+        pendingPackages: MutableSet<PackageUserKey> = mutableSetOf(),
+        unlockedUsers: LongSparseArray<Boolean> = unlockedUsersArray,
+        installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf(),
+        allDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
+    ) =
+        WorkspaceItemProcessor(
+            c = cursor,
+            memoryLogger = memoryLogger,
+            userCache = userCache,
+            userManagerState = userManagerState,
+            launcherApps = launcherApps,
+            app = app,
+            bgDataModel = bgDataModel,
+            widgetProvidersMap = widgetProvidersMap,
+            widgetInflater = widgetInflater,
+            pmHelper = pmHelper,
+            unlockedUsers = unlockedUsers,
+            iconRequestInfos = iconRequestInfos,
+            pendingPackages = pendingPackages,
+            isSdCardReady = isSdCardReady,
+            shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
+            installingPkgs = installingPkgs,
+            allDeepShortcuts = allDeepShortcuts
+        )
+
+    @Test
+    fun `When user is null then mark item deleted`() {
+        // Given
+        mockCursor = mock<LoaderCursor>().apply { id = 1 }
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When app has null intent then mark deleted`() {
+        // Given
+        mockCursor.apply { whenever(parseIntent()).thenReturn(null) }
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+        // Then
+        verify(mockCursor).markDeleted("Null intent from db for item id=1", MISSING_INFO)
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When app has null target package then mark deleted`() {
+
+        // Given
+        intent.apply {
+            component = null
+            `package` = null
+        }
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When app has empty String target package then mark deleted`() {
+
+        // Given
+        componentName = ComponentName("", "")
+        intent.component = componentName
+        intent.`package` = ""
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When valid app then mark restored`() {
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        // currently gets marked restored twice, although markRestore() has check for restoreFlag
+        verify(mockCursor, times(2)).markRestored()
+        assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+        verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
+    }
+
+    @Test
+    fun `When fallback Activity found for app then mark restored`() {
+
+        // Given
+        mockLauncherApps =
+            mock<LauncherApps>().apply {
+                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+            }
+        mockPmHelper =
+            mock<PackageManagerHelper>().apply {
+                whenever(getAppLaunchIntent(componentName.packageName, userHandle))
+                    .thenReturn(intent)
+            }
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        verify(mockCursor.updater().put(Favorites.INTENT, intent.toUri(0))).commit()
+        assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+        verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
+    }
+
+    @Test
+    fun `When app with disabled activity and no fallback found then mark deleted`() {
+
+        // Given
+        mockLauncherApps =
+            mock<LauncherApps>().apply {
+                whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+                whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+            }
+        mockPmHelper =
+            mock<PackageManagerHelper>().apply {
+                whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
+            }
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be unchanged")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(1)
+        verify(mockCursor)
+            .markDeleted(
+                "No Activities found for id=1," +
+                    " targetPkg=package," +
+                    " component=ComponentInfo{package/class}." +
+                    " Unable to create launch Intent.",
+                MISSING_INFO
+            )
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When valid Pinned Deep Shortcut then mark restored`() {
+
+        // Given
+        mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+        val expectedShortcutInfo =
+            mock<ShortcutInfo>().apply {
+                whenever(id).thenReturn("")
+                whenever(`package`).thenReturn("")
+                whenever(activity).thenReturn(mock())
+                whenever(longLabel).thenReturn("")
+                whenever(isEnabled).thenReturn(true)
+                whenever(disabledMessage).thenReturn("")
+                whenever(disabledReason).thenReturn(0)
+                whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+            }
+        val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+        keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+        iconRequestInfos = mutableListOf()
+
+        // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        assertThat(iconRequestInfos).isEmpty()
+        assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+        verify(mockCursor).markRestored()
+        verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When Pinned Deep Shortcut not found then mark deleted`() {
+
+        // Given
+        mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+        iconRequestInfos = mutableListOf()
+        keyToPinnedShortcutsMap = hashMapOf()
+
+        // When
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        assertThat(iconRequestInfos).isEmpty()
+        verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+        verify(mockCursor)
+            .markDeleted(
+                "Pinned shortcut not found from request. package=pkg, user=UserHandle{0}",
+                "shortcut_not_found"
+            )
+    }
+
+    @Test
+    fun `When valid Pinned Deep Shortcut with null intent package then use targetPkg`() {
+
+        // Given
+        mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+        val expectedShortcutInfo =
+            mock<ShortcutInfo>().apply {
+                whenever(id).thenReturn("")
+                whenever(`package`).thenReturn("")
+                whenever(activity).thenReturn(mock())
+                whenever(longLabel).thenReturn("")
+                whenever(isEnabled).thenReturn(true)
+                whenever(disabledMessage).thenReturn("")
+                whenever(disabledReason).thenReturn(0)
+                whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+            }
+        iconRequestInfos = mutableListOf()
+        // Make sure shortcuts map has expected key from expected package
+        intent.`package` = componentName.packageName
+        val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+        keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+        // set intent package back to null to test scenario
+        intent.`package` = null
+
+        // When
+        itemProcessorUnderTest =
+            createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        assertThat(iconRequestInfos).isEmpty()
+        assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+        verify(mockCursor).markRestored()
+        verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+    }
+
+    @Test
+    fun `When processing Folder then create FolderInfo and mark restored`() {
+        val actualFolderInfo = FolderInfo()
+        mockBgDataModel =
+            mock<BgDataModel>().apply { whenever(findOrMakeFolder(1)).thenReturn(actualFolderInfo) }
+        mockCursor =
+            mock<LoaderCursor>().apply {
+                user = UserHandle(0)
+                itemType = ITEM_TYPE_FOLDER
+                id = 1
+                container = 100
+                restoreFlag = 1
+                serialNumber = 101
+                whenever(applyCommonProperties(any<ItemInfo>())).then {}
+                whenever(markRestored()).doAnswer { restoreFlag = 0 }
+                whenever(getColumnIndex(Favorites.TITLE)).thenReturn(4)
+                whenever(getString(4)).thenReturn("title")
+                whenever(options).thenReturn(5)
+            }
+        val expectedFolderInfo =
+            FolderInfo().apply {
+                itemType = ITEM_TYPE_FOLDER
+                spanX = 1
+                spanY = 1
+                options = 5
+            }
+        itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+        // When
+        itemProcessorUnderTest.processItem()
+
+        // Then
+        assertWithMessage("item restoreFlag should be set to 0")
+            .that(mockCursor.restoreFlag)
+            .isEqualTo(0)
+        verify(mockCursor).markRestored()
+        assertThat(actualFolderInfo.id).isEqualTo(expectedFolderInfo.id)
+        assertThat(actualFolderInfo.container).isEqualTo(expectedFolderInfo.container)
+        assertThat(actualFolderInfo.itemType).isEqualTo(expectedFolderInfo.itemType)
+        assertThat(actualFolderInfo.screenId).isEqualTo(expectedFolderInfo.screenId)
+        assertThat(actualFolderInfo.cellX).isEqualTo(expectedFolderInfo.cellX)
+        assertThat(actualFolderInfo.cellY).isEqualTo(expectedFolderInfo.cellY)
+        assertThat(actualFolderInfo.spanX).isEqualTo(expectedFolderInfo.spanX)
+        assertThat(actualFolderInfo.spanY).isEqualTo(expectedFolderInfo.spanY)
+        assertThat(actualFolderInfo.options).isEqualTo(expectedFolderInfo.options)
+        verify(mockCursor).checkAndAddItem(actualFolderInfo, mockBgDataModel, null)
+    }
+}
diff --git a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
new file mode 100644
index 0000000..cc8e61d
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.gridmigration
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+
+class MockSet(override val size: Int) : Set<String> {
+    override fun contains(element: String): Boolean = true
+    override fun containsAll(elements: Collection<String>): Boolean = true
+    override fun isEmpty(): Boolean = false
+    override fun iterator(): Iterator<String> = listOf<String>().iterator()
+}
+
+fun itemListToBoard(itemsArg: List<WorkspaceItem>, boardSize: Point): List<CellLayoutBoard> {
+    val items = itemsArg.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+    val boardList =
+        List(items.maxOf { it.screenId + 1 }) { CellLayoutBoard(boardSize.x, boardSize.y) }
+    items.forEach {
+        when (it.type) {
+            Favorites.ITEM_TYPE_FOLDER,
+            Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+            Favorites.ITEM_TYPE_APPWIDGET ->
+                boardList[it.screenId].addWidget(it.x, it.y, it.spanX, it.spanY)
+            Favorites.ITEM_TYPE_APPLICATION -> boardList[it.screenId].addIcon(it.x, it.y)
+        }
+    }
+    return boardList
+}
+
+fun insertIntoDb(tableName: String, entry: WorkspaceItem, db: SQLiteDatabase) {
+    val values = ContentValues()
+    values.put(Favorites.SCREEN, entry.screenId)
+    values.put(Favorites.CELLX, entry.x)
+    values.put(Favorites.CELLY, entry.y)
+    values.put(Favorites.SPANX, entry.spanX)
+    values.put(Favorites.SPANY, entry.spanY)
+    values.put(Favorites.TITLE, entry.title)
+    values.put(Favorites.INTENT, entry.intent)
+    values.put(Favorites.APPWIDGET_PROVIDER, entry.appWidgetProvider)
+    values.put(Favorites.APPWIDGET_ID, entry.appWidgetId)
+    values.put(Favorites.CONTAINER, entry.container)
+    values.put(Favorites.ITEM_TYPE, entry.type)
+    values.put(Favorites._ID, entry.id)
+    db.insert(tableName, null, values)
+}
+
+fun readDb(tableName: String, db: SQLiteDatabase): List<WorkspaceItem> {
+    val result = mutableListOf<WorkspaceItem>()
+    val cursor = db.query(tableName, null, null, null, null, null, null)
+    val indexCellX: Int = cursor.getColumnIndexOrThrow(Favorites.CELLX)
+    val indexCellY: Int = cursor.getColumnIndexOrThrow(Favorites.CELLY)
+    val indexSpanX: Int = cursor.getColumnIndexOrThrow(Favorites.SPANX)
+    val indexSpanY: Int = cursor.getColumnIndexOrThrow(Favorites.SPANY)
+    val indexId: Int = cursor.getColumnIndexOrThrow(Favorites._ID)
+    val indexScreen: Int = cursor.getColumnIndexOrThrow(Favorites.SCREEN)
+    val indexTitle: Int = cursor.getColumnIndexOrThrow(Favorites.TITLE)
+    val indexAppWidgetId: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_ID)
+    val indexWidgetProvider: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER)
+    val indexIntent: Int = cursor.getColumnIndexOrThrow(Favorites.INTENT)
+    val indexItemType: Int = cursor.getColumnIndexOrThrow(Favorites.ITEM_TYPE)
+    val container: Int = cursor.getColumnIndexOrThrow(Favorites.CONTAINER)
+    while (cursor.moveToNext()) {
+        result.add(
+            WorkspaceItem(
+                x = cursor.getInt(indexCellX),
+                y = cursor.getInt(indexCellY),
+                spanX = cursor.getInt(indexSpanX),
+                spanY = cursor.getInt(indexSpanY),
+                id = cursor.getInt(indexId),
+                screenId = cursor.getInt(indexScreen),
+                title = cursor.getString(indexTitle),
+                appWidgetId = cursor.getInt(indexAppWidgetId),
+                appWidgetProvider = cursor.getString(indexWidgetProvider),
+                intent = cursor.getString(indexIntent),
+                type = cursor.getInt(indexItemType),
+                container = cursor.getInt(container)
+            )
+        )
+    }
+    return result
+}
+
+data class WorkspaceItem(
+    val x: Int,
+    val y: Int,
+    val spanX: Int,
+    val spanY: Int,
+    val id: Int,
+    val screenId: Int,
+    val title: String,
+    val appWidgetId: Int,
+    val appWidgetProvider: String,
+    val intent: String,
+    val type: Int,
+    val container: Int,
+)
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
new file mode 100644
index 0000000..58b915f
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.gridmigration
+
+import android.content.Context
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import android.os.Process
+import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.testgenerator.ValidGridMigrationTestCaseGenerator
+import com.android.launcher3.celllayout.testgenerator.generateItemsForTest
+import com.android.launcher3.model.DatabaseHelper
+import com.android.launcher3.model.DeviceGridState
+import com.android.launcher3.model.GridSizeMigrationUtil
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.provider.LauncherDbUtils
+import com.android.launcher3.util.rule.TestStabilityRule
+import com.android.launcher3.util.rule.TestStabilityRule.Stability
+import java.util.Random
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private data class Grid(val tableName: String, val size: Point, val items: List<WorkspaceItem>) {
+    fun toGridState(): DeviceGridState =
+        DeviceGridState(size.x, size.y, size.x, InvariantDeviceProfile.TYPE_PHONE, tableName)
+}
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ValidGridMigrationUnitTest {
+
+    companion object {
+        const val SEED = 1044542
+        val REPEAT_AFTER = Point(0, 10)
+        val REPEAT_AFTER_DST = Point(6, 15)
+        const val TAG = "ValidGridMigrationUnitTest"
+        const val SMALL_TEST_SIZE = 60
+        const val LARGE_TEST_SIZE = 1000
+    }
+
+    private lateinit var context: Context
+
+    @Before
+    fun setUp() {
+        context = InstrumentationRegistry.getInstrumentation().targetContext
+    }
+
+    private fun validate(srcGrid: Grid, dstGrid: Grid, resultItems: List<WorkspaceItem>) {
+        // This returns a map with the number of repeated elements
+        // ex { calculatorIcon : 6, weatherWidget : 2 }
+        val itemsToMap = { it: List<WorkspaceItem> ->
+            it.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+                .groupingBy {
+                    when (it.type) {
+                        Favorites.ITEM_TYPE_FOLDER,
+                        Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+                        Favorites.ITEM_TYPE_APPWIDGET -> it.appWidgetProvider
+                        Favorites.ITEM_TYPE_APPLICATION -> it.intent
+                        else -> it.title
+                    }
+                }
+                .eachCount()
+        }
+        resultItems.forEach {
+            assert((it.x in 0..dstGrid.size.x) && (it.y in 0..dstGrid.size.y)) {
+                "Item outside of the board size. Size = ${dstGrid.size} Item = $it"
+            }
+            assert(
+                (it.x + it.spanX in 0..dstGrid.size.x) && (it.y + it.spanY in 0..dstGrid.size.y)
+            ) {
+                "Item doesn't fit in the grid. Size = ${dstGrid.size} Item = $it"
+            }
+        }
+
+        val srcCountMap = itemsToMap(srcGrid.items)
+        val resultCountMap = itemsToMap(resultItems)
+        val diff = resultCountMap - srcCountMap
+
+        diff.forEach { (k, count) ->
+            assert(count >= 0) { "Source item $k not present on the result" }
+        }
+    }
+
+    private fun addItemsToDb(db: SQLiteDatabase, grid: Grid) {
+        LauncherDbUtils.SQLiteTransaction(db).use { transaction ->
+            grid.items.forEach { insertIntoDb(grid.tableName, it, transaction.db) }
+            transaction.commit()
+        }
+    }
+
+    private fun migrate(
+        srcGrid: Grid,
+        dstGrid: Grid,
+    ): List<WorkspaceItem> {
+        val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
+        val dbHelper =
+            DatabaseHelper(
+                context,
+                null,
+                { UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
+                {}
+            )
+
+        Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcGrid.tableName)
+
+        addItemsToDb(dbHelper.writableDatabase, srcGrid)
+        addItemsToDb(dbHelper.writableDatabase, dstGrid)
+
+        LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
+            GridSizeMigrationUtil.migrate(
+                dbHelper,
+                GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context, MockSet(1)),
+                GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context, MockSet(1)),
+                dstGrid.size.x,
+                dstGrid.size,
+                srcGrid.toGridState(),
+                dstGrid.toGridState()
+            )
+            it.commit()
+        }
+        return readDb(dstGrid.tableName, dbHelper.readableDatabase)
+    }
+
+    @Test
+    fun runTestCase() {
+        val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+        for (i in 0..SMALL_TEST_SIZE) {
+            val testCase = caseGenerator.generateTestCase(isDestEmpty = true)
+            Log.d(TAG, "Test case = $testCase")
+            val srcGrid =
+                Grid(
+                    tableName = Favorites.TMP_TABLE,
+                    size = testCase.srcSize,
+                    items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+                )
+            val dstGrid =
+                Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
+            validate(srcGrid, dstGrid, migrate(srcGrid, dstGrid))
+        }
+    }
+
+    @Test
+    fun mergeBoards() {
+        val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+        for (i in 0..SMALL_TEST_SIZE) {
+            val testCase = caseGenerator.generateTestCase(isDestEmpty = false)
+            Log.d(TAG, "Test case = $testCase")
+            val srcGrid =
+                Grid(
+                    tableName = Favorites.TMP_TABLE,
+                    size = testCase.srcSize,
+                    items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+                )
+            val dstGrid =
+                Grid(
+                    tableName = Favorites.TABLE_NAME,
+                    size = testCase.targetSize,
+                    items = generateItemsForTest(testCase.destBoards, REPEAT_AFTER_DST)
+                )
+            validate(srcGrid, dstGrid, migrate(srcGrid, dstGrid))
+        }
+    }
+
+    // This test takes about 4 minutes, there is no need to run it in presubmit.
+    @Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
+    @Test
+    fun runExtensiveTestCases() {
+        val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+        for (i in 0..LARGE_TEST_SIZE) {
+            val testCase = caseGenerator.generateTestCase(isDestEmpty = true)
+            Log.d(TAG, "Test case = $testCase")
+            val srcGrid =
+                Grid(
+                    tableName = Favorites.TMP_TABLE,
+                    size = testCase.srcSize,
+                    items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+                )
+            val dstGrid =
+                Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
+            validate(srcGrid, dstGrid, migrate(srcGrid, dstGrid))
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index 9b67310..9409ac1 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -30,7 +30,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
-    private val testContext: Context = InstrumentationRegistry.getInstrumentation().context
     private val folderName: String = "DeviceProfileDumpTest"
     @Test
     fun phonePortrait3Button() {
@@ -154,9 +153,6 @@
     }
 
     private fun assertDump(dp: DeviceProfile, filename: String) {
-        val dump = dump(context!!, dp, "${folderName}_$filename.txt")
-        val expected = readDumpFromAssets(testContext, "$folderName/$filename.txt")
-
-        assertThat(dump).isEqualTo(expected)
+        assertDump(dp, folderName, filename);
     }
 }
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index d102397..408691c 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -42,12 +42,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(145)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1445)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(177)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(177)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1445)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1435)
     }
 
     /**
@@ -64,12 +66,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(72)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1080)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(110)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(110)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1080)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1070)
     }
 
     /**
@@ -85,12 +89,14 @@
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(104)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1468)
 
         assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(370)
         assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(370)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1468)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1455)
     }
 
     /**
@@ -100,22 +106,21 @@
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
-        inv?.apply {
-            hotseatColumnSpan = IntArray(4) { 4 }
-            inlineQsb = BooleanArray(4) { false }
-        }
+        inv?.apply { inlineQsb = BooleanArray(4) { false } }
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(100)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(248)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1960)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(668)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(668)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(300)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1224)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1950)
     }
 
     /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
@@ -128,13 +133,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(91)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(233)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1885)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(640)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(640)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(287)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(287)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1179)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1875)
     }
 
     /**
@@ -150,13 +157,15 @@
 
         assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(75)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(205)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(6)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1745)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(582)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(582)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(257)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(257)
 
         assertThat(dp.isQsbInline).isFalse()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(1095)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1735)
     }
 
     @Test
@@ -176,7 +185,26 @@
 
             assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(177)
             assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(177)
-            assertThat(dp.hotseatQsbWidth).isEqualTo(1445)
+            assertThat(dp.hotseatQsbWidth).isEqualTo(1435)
         }
     }
+
+    @Test
+    fun increase_span_when_space_between_icons_is_less_than_minimum() {
+        initializeVarsForTwoPanel(isGestureMode = false, isLandscape = false, rows = 5, cols = 5)
+        val dp = newDP()
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(0)
+        assertThat(dp.numShownHotseatIcons).isEqualTo(6)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(112)
+        assertThat(dp.hotseatColumnSpan).isEqualTo(8)
+        assertThat(dp.hotseatWidthPx).isEqualTo(1383)
+
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(228)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(228)
+
+        assertThat(dp.isQsbInline).isFalse()
+        assertThat(dp.hotseatQsbWidth).isEqualTo(1372)
+    }
 }
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
new file mode 100644
index 0000000..e459956
--- /dev/null
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.popup;
+
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.os.Process;
+import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.View;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
+import com.android.launcher3.util.TestSandboxModelContextWrapper;
+import com.android.launcher3.util.UserIconInfo;
+import com.android.launcher3.views.BaseDragLayer;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemShortcutTest {
+    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+    private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+    private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
+    private View mView;
+    private ItemInfo mItemInfo;
+    private TestSandboxModelContextWrapper mTestContext;
+    private final SandboxModelContext mSandboxContext = new SandboxModelContext();
+    private PrivateProfileManager mPrivateProfileManager;
+    private PopupDataProvider mPopupDataProvider;
+    private AppInfo mAppInfo;
+    @Mock UserCache mUserCache;
+    @Mock BaseDragLayer mBaseDragLayer;
+    @Mock UserIconInfo mUserIconInfo;
+    @Mock LauncherActivityInfo mLauncherActivityInfo;
+    @Mock ApplicationInfo mApplicationInfo;
+    @Mock Intent mIntent;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
+        mTestContext = new TestSandboxModelContextWrapper(mSandboxContext);
+        mView = new View(mSandboxContext);
+        spyOn(mTestContext);
+        spyOn(mSandboxContext);
+        doReturn(mBaseDragLayer).when(mTestContext).getDragLayer();
+
+        mItemInfo = new ItemInfo();
+
+        LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class);
+        doReturn(mLauncherActivityInfo).when(mLauncherApps).resolveActivity(any(), any());
+        when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo);
+
+        when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo);
+        when(mBaseDragLayer.getChildCount()).thenReturn(0);
+        mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager();
+        spyOn(mPrivateProfileManager);
+        when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
+
+        mPopupDataProvider = mTestContext.getPopupDataProvider();
+        spyOn(mPopupDataProvider);
+    }
+
+    @After
+    public void tearDown() {
+        mSandboxContext.onDestroy();
+    }
+
+    @Test
+    public void testWidgetsForNullComponentName() {
+        assertNull(mItemInfo.getTargetComponent());
+        SystemShortcut systemShortcut = SystemShortcut.WIDGETS
+                .getShortcut(mTestContext, mItemInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testWidgetsForEmptyWidgetList() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        assertNotNull(mAppInfo.getTargetComponent());
+        doReturn(new ArrayList<>()).when(mPopupDataProvider).getWidgetsForPackageUser(any());
+        spyOn(mAppInfo);
+        SystemShortcut systemShortcut = SystemShortcut.WIDGETS
+                .getShortcut(mTestContext, mAppInfo, mView);
+        verify(mAppInfo, times(2)).getTargetComponent();
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testAppInfoShortcut() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        SystemShortcut systemShortcut = SystemShortcut.APP_INFO
+                .getShortcut(mTestContext, mAppInfo, mView);
+        assertNotNull(systemShortcut);
+    }
+
+
+    @Test
+    public void testDontSuggestAppForNonPredictedItem() {
+        assertFalse(mItemInfo.isPredictedItem());
+        SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
+                .getShortcut(mTestContext, mItemInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testDontSuggestAppForPredictedItem() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
+        assertTrue(mAppInfo.isPredictedItem());
+        SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP
+                .getShortcut(mTestContext, mAppInfo, mView);
+        assertNotNull(systemShortcut);
+        systemShortcut.onClick(mView);
+    }
+
+    @Test
+    public void testPrivateProfileInstallwithTargetComponentNull() {
+        assertNull(mItemInfo.getTargetComponent());
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mItemInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testPrivateProfileInstallNotAllAppsContainer() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION;
+
+        assertNotNull(mAppInfo.getTargetComponent());
+        assertFalse(mAppInfo.getContainerInfo().hasAllAppsContainer());
+
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mAppInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testPrivateProfileInstallNullPrivateProfileManager() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_ALL_APPS;
+        mPrivateProfileManager = null;
+
+        assertNotNull(mAppInfo.getTargetComponent());
+        assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
+        assertNull(mPrivateProfileManager);
+
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mAppInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testPrivateProfileInstallPrivateProfileManagerDisabled() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_ALL_APPS;
+
+        assertNotNull(mPrivateProfileManager);
+        assertNotNull(mAppInfo.getTargetComponent());
+        assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
+
+        when(mPrivateProfileManager.isEnabled()).thenReturn(false);
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mAppInfo, mView);
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testPrivateProfileInstallNullPrivateProfileUser() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_ALL_APPS;
+        when(mPrivateProfileManager.getProfileUser()).thenReturn(null);
+
+        assertNotNull(mPrivateProfileManager);
+        assertNotNull(mAppInfo.getTargetComponent());
+        assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
+        assertNull(mPrivateProfileManager.getProfileUser());
+
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mAppInfo, mView);
+
+        verify(mPrivateProfileManager, times(2)).getProfileUser();
+        assertNull(systemShortcut);
+    }
+
+    @Test
+    public void testPrivateProfileInstallNonNullPrivateProfileUser() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.container = CONTAINER_ALL_APPS;
+        when(mPrivateProfileManager.isEnabled()).thenReturn(true);
+        when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
+
+        assertNotNull(mAppInfo.getTargetComponent());
+        assertTrue(mAppInfo.getContainerInfo().hasAllAppsContainer());
+        assertNotNull(mPrivateProfileManager);
+        assertNotNull(mPrivateProfileManager.getProfileUser());
+        assertNull(mTestContext.getAppsView().getAppsStore().getApp(
+                new ComponentKey(mAppInfo.getTargetComponent(), PRIVATE_HANDLE)));
+
+        SystemShortcut systemShortcut = SystemShortcut.PRIVATE_PROFILE_INSTALL
+                .getShortcut(mTestContext, mAppInfo, mView);
+
+        verify(mPrivateProfileManager, times(3)).getProfileUser();
+        verify(mPrivateProfileManager).isEnabled();
+        assertNotNull(systemShortcut);
+    }
+
+    @Test
+    public void testInstallGetShortcutWithNonWorkSpaceItemInfo() {
+        SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
+                mTestContext, mItemInfo, mView);
+        Assert.assertNull(systemShortcut);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testInstallGetShortcutWithWorkSpaceItemInfo() {
+        mAppInfo = new AppInfo();
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        mAppInfo.intent = mIntent;
+        WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mAppInfo);
+        workspaceItemInfo.status = FLAG_SUPPORTS_WEB_UI;
+        SystemShortcut systemShortcut = SystemShortcut.INSTALL.getShortcut(
+                mTestContext, workspaceItemInfo, mView);
+        Assert.assertNotNull(systemShortcut);
+    }
+
+
+    @Test
+    @DisableFlags(FLAG_ENABLE_PRIVATE_SPACE)
+    public void testUninstallGetShortcutWithPrivateSpaceOff() {
+        SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
+                mTestContext, null, mView);
+        Assert.assertNull(systemShortcut);
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
+    public void testUninstallGetShortcutWithNonPrivateItemInfo() {
+        mAppInfo = new AppInfo();
+        mAppInfo.user = MAIN_HANDLE;
+        when(mUserIconInfo.isPrivate()).thenReturn(false);
+
+        SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
+                mTestContext, mAppInfo, mView);
+        verify(mUserIconInfo).isPrivate();
+        Assert.assertNull(systemShortcut);
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
+    public void testUninstallGetShortcutWithSystemItemInfo() {
+        mAppInfo = new AppInfo();
+        mAppInfo.user = PRIVATE_HANDLE;
+        mAppInfo.itemType = ITEM_TYPE_APPLICATION;
+        mAppInfo.intent = mIntent;
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
+        when(mUserIconInfo.isPrivate()).thenReturn(true);
+        // System App
+        mApplicationInfo.flags = 1;
+
+        SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
+                mTestContext, mAppInfo, mView);
+        verify(mLauncherActivityInfo, times(0)).getComponentName();
+        Assert.assertNull(systemShortcut);
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_PRIVATE_SPACE)
+    public void testUninstallGetShortcutWithPrivateItemInfo() {
+        mAppInfo = new AppInfo();
+        mAppInfo.user = PRIVATE_HANDLE;
+        mAppInfo.itemType = ITEM_TYPE_APPLICATION;
+        mAppInfo.intent = mIntent;
+        mAppInfo.componentName = new ComponentName(mTestContext, getClass());
+        when(mUserIconInfo.isPrivate()).thenReturn(true);
+        when(mLauncherActivityInfo.getComponentName()).thenReturn(mAppInfo.componentName);
+        // 3rd party app, not system app.
+        mApplicationInfo.flags = 0;
+
+        SystemShortcut systemShortcut = SystemShortcut.UNINSTALL_APP.getShortcut(
+                mTestContext, mAppInfo, mView);
+
+        verify(mLauncherActivityInfo).getComponentName();
+        Assert.assertNotNull(systemShortcut);
+
+        systemShortcut.onClick(mView);
+        verify(mSandboxContext).startActivity(any());
+    }
+}
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 10d9133..733f1e9 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -59,6 +59,7 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.backuprestore.LauncherRestoreEventLogger;
 import com.android.launcher3.model.ModelDbController;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LauncherModelHelper;
@@ -90,6 +91,7 @@
     private SQLiteDatabase mMockDb;
     private Cursor mMockCursor;
     private LauncherPrefs mPrefs;
+    private LauncherRestoreEventLogger mMockRestoreEventLogger;
 
     @Before
     public void setup() {
@@ -100,6 +102,7 @@
         mMockDb = mock(SQLiteDatabase.class);
         mMockCursor = mock(Cursor.class);
         mPrefs = new LauncherPrefs(mContext);
+        mMockRestoreEventLogger = mock(LauncherRestoreEventLogger.class);
     }
 
     @After
@@ -178,7 +181,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -207,7 +210,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm, mMockRestoreEventLogger);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -219,7 +222,7 @@
     @Test
     public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() {
         // When
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
         // Then
         assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
     }
@@ -235,7 +238,7 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -257,7 +260,7 @@
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
@@ -280,12 +283,13 @@
         when(mMockDb.query(any(), any(), any(), any(), any(), any(), any()))
                 .thenReturn(mMockCursor);
         when(mMockCursor.moveToFirst()).thenReturn(true);
+        when(mMockCursor.getColumnNames()).thenReturn(new String[] {});
         when(mMockCursor.isAfterLast()).thenReturn(true);
         RestoreDbTask.setPending(mContext);
 
         // When
         setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
-        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController, mMockRestoreEventLogger);
 
         // Then
         assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds);
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
index 9681ca8..54a1dc5 100644
--- a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
+++ b/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
@@ -84,7 +84,7 @@
                     startPadding = SizeSpec(1f.dpToPx()),
                     endPadding = SizeSpec(1f.dpToPx()),
                     gutter = SizeSpec(8f.dpToPx()),
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 )
             )
 
@@ -97,7 +97,7 @@
                     startPadding = SizeSpec(2f.dpToPx()),
                     endPadding = SizeSpec(2f.dpToPx()),
                     gutter = SizeSpec(8f.dpToPx()),
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 ),
             )
 
@@ -182,7 +182,7 @@
                     startPadding = SizeSpec(22f.dpToPx()),
                     endPadding = SizeSpec(22f.dpToPx()),
                     gutter = sizeSpec16,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 )
             )
 
@@ -231,7 +231,7 @@
                     startPadding = SizeSpec(0f.dpToPx()),
                     endPadding = SizeSpec(36f.dpToPx()),
                     gutter = sizeSpec12,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 ),
                 ResponsiveSpec(
                     maxAvailableSize = 716.dpToPx(),
@@ -240,7 +240,7 @@
                     startPadding = SizeSpec(16f.dpToPx()),
                     endPadding = SizeSpec(64f.dpToPx()),
                     gutter = sizeSpec12,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 ),
                 ResponsiveSpec(
                     maxAvailableSize = 9999.dpToPx(),
@@ -249,7 +249,7 @@
                     startPadding = SizeSpec(36f.dpToPx()),
                     endPadding = SizeSpec(80f.dpToPx()),
                     gutter = sizeSpec12,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 )
             )
 
@@ -262,7 +262,7 @@
                     startPadding = SizeSpec(0f),
                     endPadding = SizeSpec(24f.dpToPx()),
                     gutter = sizeSpec12,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 ),
                 ResponsiveSpec(
                     maxAvailableSize = 9999.dpToPx(),
@@ -271,7 +271,7 @@
                     startPadding = SizeSpec(0f),
                     endPadding = SizeSpec(34f.dpToPx()),
                     gutter = sizeSpec12,
-                    cellSize = SizeSpec(ofRemainderSpace = .25f)
+                    cellSize = SizeSpec(ofRemainderSpace = 1f)
                 ),
             )
 
diff --git a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
index 9781645..17b0ee4 100644
--- a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
+++ b/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
@@ -159,7 +159,7 @@
                     "maxSize=2147483647), " +
                     "cellSize=SizeSpec(fixedSize=0.0, " +
                     "ofAvailableSpace=0.0, " +
-                    "ofRemainderSpace=0.25, " +
+                    "ofRemainderSpace=1.0, " +
                     "matchWorkspace=false, " +
                     "maxSize=2147483647)" +
                     ")"
diff --git a/tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java
deleted file mode 100644
index d7b9638..0000000
--- a/tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.secondarydisplay;
-
-import static android.content.Context.MODE_PRIVATE;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.view.MotionEvent.ACTION_DOWN;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Intent;
-import android.graphics.Point;
-import android.os.SystemClock;
-import android.view.MotionEvent;
-import android.widget.TextView;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiObject2;
-import androidx.test.uiautomator.Until;
-
-import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
-
-import org.junit.After;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link SecondaryDisplayLauncher}.
- * TODO (b/242776943): Remove anti-patterns & migrate prediction row tests to Quickstep directory
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public final class TaplSecondaryDisplayLauncherTest extends AbstractLauncherUiTest {
-    private static final int WAIT_TIME_MS = 5000;
-    private static final int LONG_PRESS_DURATION_MS = 1000;
-    private static final int DRAG_TIME_MS = 160;
-
-    private static final String PINNED_APPS_KEY = "pinned_apps";
-
-    // Variables required to coordinate drag steps.
-    private Point mStartPoint;
-    private Point mEndPoint;
-    private long mDownTime;
-
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        setDragNDropFlag(true);
-    }
-
-    @After
-    public void tearDown() {
-        mTargetContext.getSharedPreferences(PINNED_APPS_KEY, MODE_PRIVATE)
-                .edit().clear().commit();
-    }
-
-    @Test
-    @Ignore
-    public void initializeSecondaryDisplayLauncher_allAppsButtonVisible() {
-        assertThat(findObjectByResourceName("all_apps_button")).isNotNull();
-    }
-
-    @Test
-    @Ignore
-    public void allAppsButtonTap_opensAppDrawer() {
-        openAppDrawer();
-        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
-    }
-
-    @Test
-    @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
-    public void appDrawerOpened_predictionRowAppDividerVisible() {
-        openAppDrawer();
-        assertThat(findObjectByResourceName("apps_divider_view")).isNotNull();
-    }
-
-    @Test
-    @Ignore
-    public void dragNDropDisabled_pinIconAddsToWorkspace() {
-        setDragNDropFlag(false);
-        openAppDrawer();
-        UiObject2 app = findDescendantByResourceName(
-                findObjectByResourceName("apps_list_view"), "icon");
-        app.click(LONG_PRESS_DURATION_MS);
-        UiObject2 popupContainer = findObjectByResourceName("popup_container");
-        assertThat(popupContainer).isNotNull();
-        UiObject2 pinIcon = findDescendantByTextOrDesc(popupContainer, "Add to home screen");
-        assertThat(pinIcon).isNotNull();
-        pinIcon.click();
-        String appName = app.getContentDescription();
-        assertThat(findAppInWorkspace(appName)).isNotNull();
-    }
-
-    @Test
-    @Ignore
-    public void pressBackFromAllApps_popupMenuOpen_returnsToWorkspace() {
-        openAppDrawer();
-        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
-
-        findDescendantByResourceName(findObjectByResourceName("apps_list_view"), "icon")
-                .click(LONG_PRESS_DURATION_MS);
-        assertThat(findObjectByResourceName("popup_container")).isNotNull();
-
-        // First back press should close only popup menu.
-        mDevice.pressBack();
-        assertThat(findObjectByResourceName("search_container_all_apps")).isNotNull();
-        assertThat(findObjectByResourceName("popup_container")).isNull();
-
-        // Second back press should close app drawer.
-        mDevice.pressBack();
-        assertThat(findObjectByResourceName("popup_container")).isNull();
-        assertThat(findObjectByResourceName("search_container_all_apps")).isNull();
-    }
-
-    @Test
-    @Ignore("Launcher3 without quickstep doesn't have a predictions row.")
-    public void dragNDropFromPredictionsRow_pinToGrid() {
-        openAppDrawer();
-        assertThat(findObjectByResourceName("prediction_row")).isNotNull();
-        String appName = startDragFromPredictionRow();
-        moveAppToCenterOfScreen();
-        dropApp();
-
-        // Ensure app was added.
-        assertThat(findAppInWorkspace(appName)).isNotNull();
-    }
-
-    @Test
-    @Ignore
-    public void dragNDropFromAppDrawer_pinToGrid() {
-        openAppDrawer();
-        String draggedAppName = startDragFromAllApps();
-        moveAppToCenterOfScreen();
-        dropApp();
-
-        // Ensure app was added.
-        assertThat(findAppInWorkspace(draggedAppName)).isNotNull();
-    }
-
-    @Test
-    @Ignore
-    public void tapRemoveButton_unpinApp() {
-        openAppDrawer();
-        String draggedAppName = startDragFromAllApps();
-        moveAppToCenterOfScreen();
-        dropApp();
-        removeAppByName(draggedAppName);
-        assertThat(findAppInWorkspace(draggedAppName)).isNull();
-    }
-
-    private void openAppDrawer() {
-        UiObject2 allAppsButton = findObjectByResourceName("all_apps_button");
-        assertThat(allAppsButton).isNotNull();
-        allAppsButton.click();
-    }
-
-    private String startDragFromAllApps() {
-        // Find app from app drawer.
-        UiObject2 allApps = findObjectByResourceName("apps_list_view");
-        assertThat(allApps).isNotNull();
-        UiObject2 icon = findDescendantByResourceName(allApps, "icon");
-        assertThat(icon).isNotNull();
-        String appName = icon.getContentDescription();
-
-        // Start drag action.
-        mDownTime = SystemClock.uptimeMillis();
-        mStartPoint = icon.getVisibleCenter();
-        mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
-        mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
-                LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-        assertThat(findObjectByResourceName("popup_container")).isNotNull();
-        return appName;
-    }
-
-    private String startDragFromPredictionRow() {
-        // Find app from predictions.
-        UiObject2 predictionRow = findObjectByResourceName("prediction_row");
-        assertThat(predictionRow).isNotNull();
-
-        UiObject2 icon = findDescendantByResourceName(predictionRow, "icon");
-        assertThat(icon).isNotNull();
-
-        String appName = icon.getContentDescription();
-        UiObject2 app = findDescendantByAppName(predictionRow, appName);
-        assertThat(app).isNotNull();
-
-        // Start drag action.
-        mDownTime = SystemClock.uptimeMillis();
-        mStartPoint = icon.getVisibleCenter();
-        mEndPoint = new Point(mStartPoint.x, mStartPoint.y);
-        mLauncher.sendPointer(mDownTime, mDownTime, ACTION_DOWN, mStartPoint,
-                LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-        assertThat(findObjectByResourceName("popup_container")).isNotNull();
-        return appName;
-    }
-
-    private void moveAppToCenterOfScreen() {
-        mEndPoint.set(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2);
-        mLauncher.movePointer(mDownTime, SystemClock.uptimeMillis(), DRAG_TIME_MS, true,
-                mStartPoint, mEndPoint, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-    }
-
-    private void dropApp() {
-        mLauncher.sendPointer(mDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
-                mEndPoint, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-    }
-
-    private void removeAppByName(String appName) {
-        // Find app within home screen.
-        UiObject2 app = findDescendantByAppName(findObjectByResourceName("workspace_grid"),
-                appName);
-        if (app == null) return;
-
-        // Open app's popup container.
-        app.click(LONG_PRESS_DURATION_MS);
-        UiObject2 popupContainer = findObjectByResourceName("popup_container");
-        assertThat(popupContainer).isNotNull();
-
-        // Grab & click remove button.
-        UiObject2 removeButton = findDescendantByTextOrDesc(popupContainer, "Remove");
-        assertThat(removeButton).isNotNull();
-        removeButton.click();
-    }
-
-    private UiObject2 findAppInWorkspace(String appName) {
-        UiObject2 workspace = findObjectByResourceName("workspace_grid");
-        return findDescendantByAppName(workspace, appName);
-    }
-
-    private UiObject2 findObjectByResourceName(String resourceName) {
-        return mDevice.wait(Until.findObject(By.res(mTargetPackage, resourceName)), WAIT_TIME_MS);
-    }
-
-    private UiObject2 findDescendantByResourceName(UiObject2 outerObject,
-            String resourceName) {
-        assertThat(outerObject).isNotNull();
-        return outerObject.findObject(By.res(mTargetPackage, resourceName));
-    }
-
-    private UiObject2 findDescendantByAppName(UiObject2 outerObject, String appName) {
-        assertThat(outerObject).isNotNull();
-        return outerObject.findObject(By.clazz(TextView.class).text(appName)
-                .pkg(mDevice.getLauncherPackageName()));
-    }
-
-    private UiObject2 findDescendantByTextOrDesc(UiObject2 outerObject, String content) {
-        assertThat(outerObject).isNotNull();
-        UiObject2 innerObject = outerObject.findObject(By.desc(content));
-        if (innerObject == null) innerObject = outerObject.findObject(By.text(content));
-        return innerObject;
-    }
-
-    private void startSecondaryDisplayActivity() {
-        mTargetContext.startActivity((
-                new Intent(mTargetContext, SecondaryDisplayLauncher.class).addFlags(
-                        FLAG_ACTIVITY_NEW_TASK)));
-    }
-
-    private void setDragNDropFlag(Boolean status) {
-        startSecondaryDisplayActivity();
-    }
-}
diff --git a/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java
new file mode 100644
index 0000000..b6ded97
--- /dev/null
+++ b/tests/src/com/android/launcher3/tapl/TaplUtilityTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.tapl;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class TaplUtilityTest {
+
+    @Test
+    public void testMakeMultilinePattern() {
+        // Original title will match.
+        assertTrue(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play Store").matches());
+        assertTrue(AppIcon.makeMultilinePattern("PlayStore")
+                .matcher("PlayStore").matches());
+
+        // Original title with whitespace added will match.
+        assertTrue(AppIcon.makeMultilinePattern("PlayStore")
+                .matcher("Play\nStore").matches());
+        assertTrue(AppIcon.makeMultilinePattern("PlayStore")
+                .matcher("Play Store").matches());
+        // Original title with whitespace removed will also match.
+        assertTrue(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("PlayStore").matches());
+        // Or whitespace replaced with a different kind of whitespace (both of above conditions).
+        assertTrue(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play\nStore").matches());
+        assertTrue(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play \n Store").matches());
+
+        // Any non-whitespace character added to the title will not match.
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play Store has 7 notifications").matches());
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play  Store!").matches());
+        // Title is case-sensitive.
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("play store").matches());
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("play  store").matches());
+        // Removing non whitespace characters will not match.
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("").matches());
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play Stor").matches());
+        assertFalse(AppIcon.makeMultilinePattern("Play Store")
+                .matcher("Play").matches());
+    }
+}
diff --git a/tests/src/com/android/launcher3/tapl/TaplUtilityTests.java b/tests/src/com/android/launcher3/tapl/TaplUtilityTests.java
deleted file mode 100644
index 15db1d8..0000000
--- a/tests/src/com/android/launcher3/tapl/TaplUtilityTests.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.tapl;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class TaplUtilityTests {
-
-    @Test
-    public void testNewStringWithRegex() {
-        assertTrue(AppIcon.makeMultilinePattern("Play Store")
-                .matcher("Play Store has 7 notifications").matches());
-        assertTrue(AppIcon.makeMultilinePattern("Play Store")
-                .matcher("Play  Store!").matches());
-        assertFalse(AppIcon.makeMultilinePattern("Play Store")
-                .matcher("play  store").matches());
-        assertFalse(AppIcon.makeMultilinePattern("Play Store")
-                .matcher("").matches());
-        assertTrue(AppIcon.makeMultilinePattern("Play Store")
-                .matcher("Play \n Store").matches());
-    }
-}
diff --git a/tests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java b/tests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java
new file mode 100644
index 0000000..0f5117b
--- /dev/null
+++ b/tests/src/com/android/launcher3/testcomponent/UnarchiveBroadcastReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.testcomponent;
+
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Broadcast Receiver to receive app unarchival broadcast. It is used to fulfill archiving
+ * platform requirements.
+ */
+public class UnarchiveBroadcastReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+    }
+}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 79d8c60..9c289d6 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,16 +15,21 @@
  */
 package com.android.launcher3.ui;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
+import static com.android.launcher3.testing.shared.TestProtocol.WIDGET_CONFIG_NULL_EXTRA_INTENT;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
+import android.app.ActivityOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -55,18 +60,17 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.celllayout.FavoriteItemsTransaction;
 import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.tapl.HomeAppIcon;
 import com.android.launcher3.tapl.LauncherInstrumentation;
-import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
 import com.android.launcher3.tapl.TestHelpers;
 import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
 import com.android.launcher3.util.rule.FailureWatcher;
 import com.android.launcher3.util.rule.SamplerRule;
 import com.android.launcher3.util.rule.ScreenRecordRule;
@@ -83,6 +87,7 @@
 import org.junit.rules.TestRule;
 
 import java.io.IOException;
+import java.util.Objects;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -94,7 +99,7 @@
 /**
  * Base class for all instrumentation tests providing various utility methods.
  */
-public abstract class AbstractLauncherUiTest {
+public abstract class AbstractLauncherUiTest<LAUNCHER_TYPE extends Launcher> {
 
     public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
     public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
@@ -192,6 +197,7 @@
 
     protected AbstractLauncherUiTest() {
         mLauncher.enableCheckEventsForSuccessfulGestures();
+        mLauncher.setAnomalyChecker(AbstractLauncherUiTest::verifyKeyguardInvisible);
         try {
             mDevice.setOrientationNatural();
         } catch (RemoteException e) {
@@ -202,10 +208,6 @@
             mLauncher.setSystemHealthSupplier(startTime -> TestCommandReceiver.callCommand(
                             TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE, startTime.toString())
                     .getString("result"));
-            mLauncher.setOnSettledStateAction(
-                    containerType -> executeOnLauncher(
-                            launcher ->
-                                    checkLauncherIntegrity(launcher, containerType)));
         }
         mLauncher.enableDebugTracing();
         // Avoid double-reporting of Launcher crashes.
@@ -222,15 +224,13 @@
     @Rule
     public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
 
-    public static void initialize(AbstractLauncherUiTest test) throws Exception {
-        initialize(test, false);
-    }
+    @Rule
+    public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
 
-    public static void initialize(
-            AbstractLauncherUiTest test, boolean clearWorkspace) throws Exception {
-        test.reinitializeLauncherData(clearWorkspace);
+    public static void initialize(AbstractLauncherUiTest test) throws Exception {
+        test.reinitializeLauncherData();
         test.mDevice.pressHome();
-        test.waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
+        test.waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
         test.waitForState("Launcher internal state didn't switch to Home",
                 () -> LauncherState.NORMAL);
         test.waitForResumed("Launcher internal state is still Background");
@@ -255,7 +255,7 @@
         final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
                 Launcher.ACTIVITY_TRACKER::getCreatedActivity);
         final RuleChain inner = RuleChain
-                .outerRule(new PortraitLandscapeRunner(this))
+                .outerRule(new PortraitLandscapeRunner<LAUNCHER_TYPE>(this))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
                 // .around(viewCaptureRule) // b/315482167
                 .around(new TestIsolationRule(mLauncher, true));
@@ -304,12 +304,15 @@
         if (userManager != null) {
             for (UserHandle userHandle : userManager.getUserProfiles()) {
                 if (!userHandle.isSystem()) {
-                    mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
+                    mDevice.executeShellCommand(
+                            "pm remove-user --wait " + userHandle.getIdentifier());
                 }
             }
         }
 
         onTestStart();
+
+        initialize(this);
     }
 
     /** Method that should be called when a test starts. */
@@ -370,7 +373,8 @@
         Assert.assertTrue("Setup wizard is still visible", wizardDismissed);
     }
 
-    private static void verifyKeyguardInvisible() {
+    /** Asserts that keyguard is not visible */
+    public static void verifyKeyguardInvisible() {
         final boolean keyguardAlreadyVisible = sSeenKeyguard;
 
         sSeenKeyguard = sSeenKeyguard
@@ -427,12 +431,12 @@
         }
     }
 
-    protected <T> T getFromLauncher(Function<Launcher, T> f) {
+    protected <T> T getFromLauncher(Function<LAUNCHER_TYPE, T> f) {
         if (!TestHelpers.isInLauncherProcess()) return null;
         return getOnUiThread(() -> f.apply(Launcher.ACTIVITY_TRACKER.getCreatedActivity()));
     }
 
-    protected void executeOnLauncher(Consumer<Launcher> f) {
+    protected void executeOnLauncher(Consumer<LAUNCHER_TYPE> f) {
         getFromLauncher(launcher -> {
             f.accept(launcher);
             return null;
@@ -442,7 +446,7 @@
     // Execute an action on Launcher, but forgive it when launcher is null.
     // Launcher can be null if teardown is happening after a failed setup step where launcher
     // activity failed to be created.
-    protected void executeOnLauncherInTearDown(Consumer<Launcher> f) {
+    protected void executeOnLauncherInTearDown(Consumer<LAUNCHER_TYPE> f) {
         executeOnLauncher(launcher -> {
             if (launcher != null) f.accept(launcher);
         });
@@ -470,20 +474,20 @@
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
     protected void waitForLauncherCondition(String
-            message, Function<Launcher, Boolean> condition) {
+            message, Function<LAUNCHER_TYPE, Boolean> condition) {
         waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT);
     }
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
-    protected <T> T getOnceNotNull(String message, Function<Launcher, T> f) {
+    protected <O> O getOnceNotNull(String message, Function<LAUNCHER_TYPE, O> f) {
         return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT);
     }
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
     protected void waitForLauncherCondition(
-            String message, Function<Launcher, Boolean> condition, long timeout) {
+            String message, Function<LAUNCHER_TYPE, Boolean> condition, long timeout) {
         verifyKeyguardInvisible();
         if (!TestHelpers.isInLauncherProcess()) return;
         Wait.atMost(message, () -> getFromLauncher(condition), timeout, mLauncher);
@@ -491,7 +495,7 @@
 
     // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
     // flakiness.
-    protected <T> T getOnceNotNull(String message, Function<Launcher, T> f, long timeout) {
+    protected <T> T getOnceNotNull(String message, Function<LAUNCHER_TYPE, T> f, long timeout) {
         if (!TestHelpers.isInLauncherProcess()) return null;
 
         final Object[] output = new Object[1];
@@ -507,7 +511,7 @@
     // flakiness.
     protected void waitForLauncherCondition(
             String message,
-            Runnable testThreadAction, Function<Launcher, Boolean> condition,
+            Runnable testThreadAction, Function<LAUNCHER_TYPE, Boolean> condition,
             long timeout) {
         if (!TestHelpers.isInLauncherProcess()) return;
         Wait.atMost(message, () -> {
@@ -536,13 +540,23 @@
 
         @Override
         public void onReceive(Context context, Intent intent) {
+            Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, intent == null
+                    ? "AbstractLauncherUiTest.onReceive(): inputted intent NULL"
+                    : "AbstractLauncherUiTest.onReceive(): inputted intent NOT NULL");
             mIntent = intent;
             latch.countDown();
+            Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
+                    "AbstractLauncherUiTest.onReceive() Countdown Latch started");
         }
 
         public Intent blockingGetIntent() throws InterruptedException {
+            Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
+                    "AbstractLauncherUiTest.blockingGetIntent()");
             latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
             mTargetContext.unregisterReceiver(this);
+            Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, mIntent == null
+                    ? "AbstractLauncherUiTest.onReceive(): mIntent NULL"
+                    : "AbstractLauncherUiTest.onReceive(): mIntent NOT NULL");
             return mIntent;
         }
 
@@ -561,16 +575,35 @@
                 true /* newTask */);
     }
 
-    public static void startTestActivity(int activityNumber) {
+    /** alternative of startAppFast where app is guaranteed to launch in fullscreen mode */
+    public static void startAppFastInFullscreen(String packageName) {
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        options.setLaunchDisplayId(DEFAULT_DISPLAY);
+        options.setLaunchActivityType(ACTIVITY_TYPE_STANDARD);
+
+        startIntent(
+                getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage(
+                        packageName),
+                By.pkg(packageName).depth(0),
+                true /* newTask */,
+                options);
+    }
+
+    public static void startTestActivity(String activityName, String activityLabel) {
         final String packageName = getAppPackageName();
         final Intent intent = getInstrumentation().getContext().getPackageManager().
                 getLaunchIntentForPackage(packageName);
         intent.setComponent(new ComponentName(packageName,
-                "com.android.launcher3.tests.Activity" + activityNumber));
-        startIntent(intent, By.pkg(packageName).text("TestActivity" + activityNumber),
+                "com.android.launcher3.tests." + activityName));
+        startIntent(intent, By.pkg(packageName).text(activityLabel),
                 false /* newTask */);
     }
 
+    public static void startTestActivity(int activityNumber) {
+        startTestActivity("Activity" + activityNumber, "TestActivity" + activityNumber);
+    }
+
     public static void startImeTestActivity() {
         final String packageName = getAppPackageName();
         final Intent intent = getInstrumentation().getContext().getPackageManager().
@@ -581,7 +614,19 @@
                 false /* newTask */);
     }
 
-    private static void startIntent(Intent intent, BySelector selector, boolean newTask) {
+    /** Starts ExcludeFromRecentsTestActivity, which has excludeFromRecents="true". */
+    public static void startExcludeFromRecentsTestActivity() {
+        final String packageName = getAppPackageName();
+        final Intent intent = getInstrumentation().getContext().getPackageManager()
+                .getLaunchIntentForPackage(packageName);
+        intent.setComponent(new ComponentName(packageName,
+                "com.android.launcher3.testcomponent.ExcludeFromRecentsTestActivity"));
+        startIntent(intent, By.pkg(packageName).text("ExcludeFromRecentsTestActivity"),
+                false /* newTask */);
+    }
+
+    private static void startIntent(
+            Intent intent, BySelector selector, boolean newTask, ActivityOptions options) {
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         if (newTask) {
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -589,7 +634,12 @@
             intent.addFlags(
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
         }
-        getInstrumentation().getTargetContext().startActivity(intent);
+
+        if (options != null) {
+            getInstrumentation().getTargetContext().startActivity(intent, options.toBundle());
+        } else {
+            getInstrumentation().getTargetContext().startActivity(intent);
+        }
         assertTrue("App didn't start: " + selector,
                 TestHelpers.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT));
 
@@ -600,6 +650,10 @@
                 DEFAULT_ACTIVITY_TIMEOUT, launcherInstrumentation);
     }
 
+    private static void startIntent(Intent intent, BySelector selector, boolean newTask) {
+        startIntent(intent, selector, newTask, null);
+    }
+
     public static ActivityInfo resolveSystemAppInfo(String category) {
         return getInstrumentation().getContext().getPackageManager().resolveActivity(
                 new Intent(Intent.ACTION_MAIN).addCategory(category),
@@ -624,7 +678,7 @@
                 "Launcher still active", launcher -> launcher == null, DEFAULT_UI_TIMEOUT);
     }
 
-    protected boolean isInLaunchedApp(Launcher launcher) {
+    protected boolean isInLaunchedApp(LAUNCHER_TYPE launcher) {
         return launcher == null || !launcher.hasBeenResumed();
     }
 
@@ -634,91 +688,11 @@
                 launcher -> launcher.getStateManager().getState() == state.get());
     }
 
-    protected int getAllAppsScroll(Launcher launcher) {
+    protected int getAllAppsScroll(LAUNCHER_TYPE launcher) {
         return launcher.getAppsView().getActiveRecyclerView().computeVerticalScrollOffset();
     }
 
-    private void checkLauncherIntegrity(
-            Launcher launcher, ContainerType expectedContainerType) {
-        if (launcher != null) {
-            final StateManager<LauncherState> stateManager = launcher.getStateManager();
-            final LauncherState stableState = stateManager.getCurrentStableState();
-
-            assertTrue("Stable state != state: " + stableState.getClass().getSimpleName() + ", "
-                            + stateManager.getState().getClass().getSimpleName(),
-                    stableState == stateManager.getState());
-
-            final boolean isResumed = launcher.hasBeenResumed();
-            final boolean isStarted = launcher.isStarted();
-            checkLauncherState(launcher, expectedContainerType, isResumed, isStarted);
-
-            final int ordinal = stableState.ordinal;
-
-            switch (expectedContainerType) {
-                case WORKSPACE:
-                case WIDGETS: {
-                    assertTrue(
-                            "Launcher is not resumed in state: " + expectedContainerType,
-                            isResumed);
-                    assertTrue(TestProtocol.stateOrdinalToString(ordinal),
-                            ordinal == TestProtocol.NORMAL_STATE_ORDINAL);
-                    break;
-                }
-                case HOME_ALL_APPS: {
-                    assertTrue(
-                            "Launcher is not resumed in state: " + expectedContainerType,
-                            isResumed);
-                    assertTrue(TestProtocol.stateOrdinalToString(ordinal),
-                            ordinal == TestProtocol.ALL_APPS_STATE_ORDINAL);
-                    break;
-                }
-                case OVERVIEW: {
-                    verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
-                            ordinal, TestProtocol.OVERVIEW_STATE_ORDINAL);
-                    break;
-                }
-                case SPLIT_SCREEN_SELECT: {
-                    verifyOverviewState(launcher, expectedContainerType, isStarted, isResumed,
-                            ordinal, TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL);
-                    break;
-                }
-                case TASKBAR_ALL_APPS:
-                case LAUNCHED_APP: {
-                    assertTrue("Launcher is resumed in state: " + expectedContainerType,
-                            !isResumed);
-                    assertTrue(TestProtocol.stateOrdinalToString(ordinal),
-                            ordinal == TestProtocol.NORMAL_STATE_ORDINAL);
-                    break;
-                }
-                default:
-                    throw new IllegalArgumentException(
-                            "Illegal container: " + expectedContainerType);
-            }
-        } else {
-            assertTrue(
-                    "Container type is not LAUNCHED_APP, TASKBAR_ALL_APPS "
-                            + "or FALLBACK_OVERVIEW: " + expectedContainerType,
-                    expectedContainerType == ContainerType.LAUNCHED_APP
-                            || expectedContainerType == ContainerType.TASKBAR_ALL_APPS
-                            || expectedContainerType == ContainerType.FALLBACK_OVERVIEW);
-        }
-    }
-
-    protected void checkLauncherState(Launcher launcher, ContainerType expectedContainerType,
-            boolean isResumed, boolean isStarted) {
-        assertTrue("hasBeenResumed() != isStarted(), hasBeenResumed(): " + isResumed,
-                isResumed == isStarted);
-        assertTrue("hasBeenResumed() != isUserActive(), hasBeenResumed(): " + isResumed,
-                isResumed == launcher.isUserActive());
-    }
-
-    protected void checkLauncherStateInOverview(Launcher launcher,
-            ContainerType expectedContainerType, boolean isStarted, boolean isResumed) {
-        assertTrue("Launcher is not resumed in state: " + expectedContainerType,
-                isResumed);
-    }
-
-    protected void onLauncherActivityClose(Launcher launcher) {
+    protected void onLauncherActivityClose(LAUNCHER_TYPE launcher) {
     }
 
     protected HomeAppIcon createShortcutInCenterIfNotExist(String name) {
@@ -747,9 +721,11 @@
         return homeAppIcon;
     }
 
-    private void verifyOverviewState(Launcher launcher, ContainerType expectedContainerType,
-            boolean isStarted, boolean isResumed, int ordinal, int expectedOrdinal) {
-        checkLauncherStateInOverview(launcher, expectedContainerType, isStarted, isResumed);
-        assertEquals(TestProtocol.stateOrdinalToString(ordinal), ordinal, expectedOrdinal);
+    protected void commitTransactionAndLoadHome(FavoriteItemsTransaction transaction) {
+        transaction.commit();
+
+        // Launch the home activity
+        UiDevice.getInstance(getInstrumentation()).pressHome();
+        mLauncher.waitForLauncherInitialized();
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 58af51c..90ded10 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -22,7 +22,7 @@
 import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
 import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT;
 import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_SMALL;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS;
+import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -39,6 +39,7 @@
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -46,7 +47,6 @@
 import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.views.BaseDragLayer;
 
 import org.junit.Before;
@@ -96,12 +96,14 @@
     private Context mContext;
     private int mLimitedWidth;
     private AppInfo mGmailAppInfo;
+    private LauncherPrefs mLauncherPrefs;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         Utilities.enableRunningInTestHarnessForTests();
         mContext = new ActivityContextWrapper(getApplicationContext());
+        mLauncherPrefs = LauncherPrefs.get(mContext);
         mBubbleTextView = new BubbleTextView(mContext);
         mBubbleTextView.reset();
 
@@ -129,190 +131,155 @@
 
     @Test
     public void testEmptyString_flagOn() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            mItemInfoWithIcon.title = EMPTY_STRING;
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        mItemInfoWithIcon.title = EMPTY_STRING;
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines());
     }
 
     @Test
     public void testEmptyString_flagOff() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
-            mItemInfoWithIcon.title = EMPTY_STRING;
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mItemInfoWithIcon.title = EMPTY_STRING;
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testStringWithSpaceLongerThanCharLimit_flagOn() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "Battery Stats"
-            mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "Battery Stats"
+        mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testStringWithSpaceLongerThanCharLimit_flagOff() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
-            // test string: "Battery Stats"
-            mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        // test string: "Battery Stats"
+        mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringNoSpaceLongerThanCharLimit_flagOn() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "flutterappflorafy"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "flutterappflorafy"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringNoSpaceLongerThanCharLimit_flagOff() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
-            // test string: "flutterappflorafy"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        // test string: "flutterappflorafy"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringWithSpaceLongerThanCharLimit_flagOn() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "System UWB Field Test"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "System UWB Field Test"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringWithSpaceLongerThanCharLimit_flagOff() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
-            // test string: "System UWB Field Test"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        // test string: "System UWB Field Test"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringSymbolLongerThanCharLimit_flagOn() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "LEGO®Builder"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "LEGO®Builder"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void testLongStringSymbolLongerThanCharLimit_flagOff() {
-        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
-            // test string: "LEGO®Builder"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        // test string: "LEGO®Builder"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
@@ -373,58 +340,49 @@
 
     @Test
     public void testEnsurePredictionRowIsTwoLine() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "Battery Stats"
-            mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "Battery Stats"
+        mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void modifyTitleToSupportMultiLine_whenLimitedHeight_shouldBeOneLine() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "LEGO®Builder"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "LEGO®Builder"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
     public void modifyTitleToSupportMultiLine_whenUnlimitedHeight_shouldBeTwoLine() {
-        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
-        try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
-            // test string: "LEGO®Builder"
-            mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
-            mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
-            mBubbleTextView.applyLabel(mItemInfoWithIcon);
-            mBubbleTextView.setTypeface(Typeface.MONOSPACE);
-            mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+        mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+        // test string: "LEGO®Builder"
+        mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+        mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+        mBubbleTextView.applyLabel(mItemInfoWithIcon);
+        mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+        mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
 
-            mBubbleTextView.onPreDraw();
+        mBubbleTextView.onPreDraw();
 
-            assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
+        assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index d94e4a5..c4e74f2 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -3,8 +3,9 @@
 import android.util.Log;
 import android.view.Surface;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.tapl.TestHelpers;
-import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.rule.FailureWatcher;
 
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
@@ -14,10 +15,12 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
-public class PortraitLandscapeRunner implements TestRule {
+public class PortraitLandscapeRunner<LAUNCHER_TYPE extends Launcher> implements TestRule {
     private static final String TAG = "PortraitLandscapeRunner";
-    private AbstractLauncherUiTest mTest;
+    private AbstractLauncherUiTest<LAUNCHER_TYPE> mTest;
 
     // Annotation for tests that need to be run in portrait and landscape modes.
     @Retention(RetentionPolicy.RUNTIME)
@@ -25,18 +28,14 @@
     public @interface PortraitLandscape {
     }
 
-    public PortraitLandscapeRunner(AbstractLauncherUiTest test) {
+    public PortraitLandscapeRunner(AbstractLauncherUiTest<LAUNCHER_TYPE> test) {
         mTest = test;
     }
 
     @Override
     public Statement apply(Statement base, Description description) {
         if (!TestHelpers.isInLauncherProcess()
-                || description.getAnnotation(PortraitLandscape.class) == null
-                // If running in presubmit, don't run in both orientations.
-                // It's important to keep presubmits fast even if we will occasionally miss
-                // regressions in presubmit.
-                || TestStabilityRule.isPresubmit()) {
+                || description.getAnnotation(PortraitLandscape.class) == null) {
             return base;
         }
 
@@ -44,13 +43,23 @@
             @Override
             public void evaluate() throws Throwable {
                 try {
-                    mTest.mDevice.pressHome();
-                    mTest.waitForLauncherCondition("Launcher activity wasn't created",
-                            launcher -> launcher != null);
+                    try {
+                        // we expect to begin unlocked...
+                        AbstractLauncherUiTest.verifyKeyguardInvisible();
 
-                    mTest.executeOnLauncher(launcher ->
-                            launcher.getRotationHelper().forceAllowRotationForTesting(
-                                    true));
+                        mTest.mDevice.pressHome();
+                        mTest.waitForLauncherCondition("Launcher activity wasn't created",
+                                Objects::nonNull,
+                                TimeUnit.SECONDS.toMillis(20));
+
+                        mTest.executeOnLauncher(launcher ->
+                                launcher.getRotationHelper().forceAllowRotationForTesting(
+                                        true));
+
+                    } catch (Throwable e) {
+                        FailureWatcher.onError(mTest.mLauncher, description, e);
+                        throw e;
+                    }
 
                     evaluateInPortrait();
                     evaluateInLandscape();
@@ -66,6 +75,9 @@
                         }
                     });
                     mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
+
+                    // and end unlocked...
+                    AbstractLauncherUiTest.verifyKeyguardInvisible();
                 }
             }
 
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
similarity index 79%
rename from tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
rename to tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
index 229ea45..4a67600 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
@@ -21,20 +21,19 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
-import org.junit.Before;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
+public class TaplTestsLauncher3Test extends AbstractLauncherUiTest<Launcher> {
 
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
-
+    @KeepRecordOnSuccess
+    @ScreenRecord // b/322823478
     @Test
     public void testDevicePressMenu() throws Exception {
         mDevice.pressMenu();
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index f818564..70a3dd0 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -19,7 +19,10 @@
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 import static com.android.launcher3.util.TestUtil.installDummyAppForUser;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -29,7 +32,10 @@
 import android.view.View;
 
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
@@ -39,16 +45,22 @@
 import com.android.launcher3.allapps.WorkProfileManager;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.Objects;
 import java.util.function.Predicate;
 
-public class TaplWorkProfileTest extends AbstractLauncherUiTest {
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TaplWorkProfileTest extends AbstractLauncherUiTest<Launcher> {
 
     private static final int WORK_PAGE = ActivityAllAppsContainerView.AdapterHolder.WORK;
 
@@ -60,6 +72,7 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
+        initialize(this);
         String output =
                 mDevice.executeShellCommand(
                         "pm create-user --profileOf 0 --managed TestProfile");
@@ -98,7 +111,17 @@
             launcher.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
         });
         TestUtil.uninstallDummyApp();
-        mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
+
+        mLauncher.runToState(
+                () -> {
+                    try {
+                        mDevice.executeShellCommand("pm remove-user --wait " + mProfileUserId);
+                    } catch (IOException e) {
+                        throw new RuntimeException(e);
+                    }
+                },
+                NORMAL_STATE_ORDINAL,
+                "executing pm 'remove-user' command");
     }
 
     private void waitForWorkTabSetup() {
@@ -112,6 +135,7 @@
     }
 
     @Test
+    @com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord // b/325383911
     public void workTabExists() {
         assumeTrue(mWorkProfileSetupSuccessful);
         waitForWorkTabSetup();
@@ -123,8 +147,10 @@
                 LauncherInstrumentation.WAIT_TIME_MS);
     }
 
+    // Staging; will be promoted to presubmit if stable
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+    @ScreenRecord
     @Test
-    @Ignore("b/243855320")
     public void toggleWorks() {
         assumeTrue(mWorkProfileSetupSuccessful);
         waitForWorkTabSetup();
@@ -171,6 +197,8 @@
 
     }
 
+    @KeepRecordOnSuccess
+    @ScreenRecord // b/322823478
     @Test
     public void testEdu() {
         assumeTrue(mWorkProfileSetupSuccessful);
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
index d96287f..e6e02b4 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
@@ -52,7 +52,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest {
+public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest<Launcher> {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -87,7 +87,7 @@
      * @param acceptConfig accept the config activity
      */
     private void runTest(boolean acceptConfig) throws Throwable {
-        new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
 
         // Drag widget to homescreen
         WidgetConfigStartupMonitor monitor = new WidgetConfigStartupMonitor();
@@ -161,11 +161,12 @@
 
         public int getWidgetId() throws InterruptedException {
             Intent intent = blockingGetExtraIntent();
-            assertNotNull(intent);
-            assertEquals(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
+            assertNotNull("Null EXTRA_INTENT", intent);
+            assertEquals("Intent action is not ACTION_APPWIDGET_CONFIGURE",
+                    AppWidgetManager.ACTION_APPWIDGET_CONFIGURE, intent.getAction());
             int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                     LauncherAppWidgetInfo.NO_ID);
-            assertNotSame(widgetId, LauncherAppWidgetInfo.NO_ID);
+            assertNotSame("Widget id is NO_ID", widgetId, LauncherAppWidgetInfo.NO_ID);
             return widgetId;
         }
     }
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index 27fda9b..7845dec 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -15,24 +15,29 @@
  */
 package com.android.launcher3.ui.widget;
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
 import static org.junit.Assert.assertNotNull;
 
 import android.platform.test.annotations.PlatinumTest;
-import android.platform.test.rule.ScreenRecordRule;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.celllayout.FavoriteItemsTransaction;
 import com.android.launcher3.tapl.Widget;
 import com.android.launcher3.tapl.WidgetResizeFrame;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.ui.TestViewHelpers;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.ShellCommandRule;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
-import org.junit.Ignore;
+import org.junit.Assume;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -42,18 +47,17 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplAddWidgetTest extends AbstractLauncherUiTest {
+public class TaplAddWidgetTest extends AbstractLauncherUiTest<Launcher> {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
 
-    @PlatinumTest(focusArea = "launcher")
     @Test
     @PortraitLandscape
-    @ScreenRecordRule.ScreenRecord // b/289161193
+    @ScreenRecord // b/316910614
     public void testDragIcon() throws Throwable {
         mLauncher.enableDebugTracing(); // b/289161193
-        new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
 
         waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
 
@@ -82,11 +86,14 @@
      * A custom shortcut is a 1x1 widget that launches a specific intent when user tap on it.
      * Custom shortcuts are replaced by deep shortcuts after api 25.
      */
-    @Ignore
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     @PortraitLandscape
     public void testDragCustomShortcut() throws Throwable {
-        new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
+        // TODO(b/322820039): Enable test for tablets - the picker UI has changed and test needs to
+        //  be updated to look for appropriate UI elements.
+        Assume.assumeFalse(mLauncher.isTablet());
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
 
         mLauncher.getWorkspace().openAllWidgets()
                 .getWidget("com.android.launcher3.testcomponent.CustomShortcutConfigActivity")
@@ -98,10 +105,12 @@
     /**
      * Test dragging a widget to the workspace and resize it.
      */
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/316910614
     @PlatinumTest(focusArea = "launcher")
     @Test
+    @ScreenRecord // b/316910614
     public void testResizeWidget() throws Throwable {
-        new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
 
         waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
 
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
index 6aa746d..28d1faa 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
@@ -43,6 +43,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
@@ -76,7 +77,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplBindWidgetTest extends AbstractLauncherUiTest {
+public class TaplBindWidgetTest extends AbstractLauncherUiTest<Launcher> {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -251,22 +252,20 @@
     private void addPendingItemToScreen(LauncherAppWidgetInfo item, int restoreStatus) {
         item.restoreStatus = restoreStatus;
         item.screenId = FIRST_SCREEN_ID;
-        new FavoriteItemsTransaction(mTargetContext)
-                .addItem(() -> item)
-                .commitAndLoadHome(mLauncher);
+        commitTransactionAndLoadHome(
+                new FavoriteItemsTransaction(mTargetContext).addItem(() -> item));
     }
 
     private LauncherAppWidgetProviderInfo addWidgetToScreen(boolean hasConfigureScreen,
             boolean bindWidget, Consumer<LauncherAppWidgetInfo> itemOverride) {
         LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(hasConfigureScreen);
-        new FavoriteItemsTransaction(mTargetContext)
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
                 .addItem(() -> {
                     LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, bindWidget);
                     item.screenId = FIRST_SCREEN_ID;
                     itemOverride.accept(item);
                     return item;
-                })
-                .commitAndLoadHome(mLauncher);
+                }));
         return info;
     }
 
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
index f12f961..74047f0 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
@@ -59,7 +59,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplRequestPinItemTest extends AbstractLauncherUiTest {
+public class TaplRequestPinItemTest extends AbstractLauncherUiTest<Launcher> {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -74,7 +74,6 @@
         super.setUp();
         mCallbackAction = UUID.randomUUID().toString();
         mShortcutId = UUID.randomUUID().toString();
-        AbstractLauncherUiTest.initialize(this);
     }
 
     @Test
@@ -129,7 +128,7 @@
 
     private void runTest(String activityMethod, boolean isWidget, ItemOperator itemMatcher,
             Intent... commandIntents) throws Throwable {
-        new FavoriteItemsTransaction(mTargetContext).commitAndLoadHome(mLauncher);
+        commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext));
 
         // Open Pin item activity
         BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
index bc73683..19c5850 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
@@ -30,7 +30,6 @@
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -40,13 +39,7 @@
  */
 @MediumTest
 @RunWith(AndroidJUnit4.class)
-public class TaplWidgetPickerTest extends AbstractLauncherUiTest {
-
-    @Before
-    public void setUp() throws Exception {
-        super.setUp();
-        initialize(this);
-    }
+public class TaplWidgetPickerTest extends AbstractLauncherUiTest<Launcher> {
 
     private WidgetsRecyclerView getWidgetsView(Launcher launcher) {
         return WidgetsFullSheet.getWidgetsView(launcher);
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
index a3d3344..d653317 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
@@ -31,6 +31,7 @@
 import androidx.test.filters.LargeTest;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.icons.ThemedIconDrawable;
 import com.android.launcher3.tapl.HomeAllApps;
 import com.android.launcher3.tapl.HomeAppIcon;
@@ -49,7 +50,7 @@
  * Note running these tests will clear the workspace on the device.
  */
 @LargeTest
-public class TaplThemeIconsTest extends AbstractLauncherUiTest {
+public class TaplThemeIconsTest extends AbstractLauncherUiTest<Launcher> {
 
     private static final String APP_NAME = "IconThemedActivity";
     private static final String SHORTCUT_NAME = "Shortcut 1";
@@ -57,7 +58,7 @@
     @Test
     public void testIconWithoutTheme() throws Exception {
         setThemeEnabled(false);
-        AbstractLauncherUiTest.initialize(this);
+        initialize(this);
 
         HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
         allApps.freeze();
@@ -75,7 +76,7 @@
     @Test
     public void testShortcutIconWithoutTheme() throws Exception {
         setThemeEnabled(false);
-        AbstractLauncherUiTest.initialize(this);
+        initialize(this);
 
         HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
         allApps.freeze();
@@ -94,7 +95,7 @@
     @Test
     public void testIconWithTheme() throws Exception {
         setThemeEnabled(true);
-        AbstractLauncherUiTest.initialize(this);
+        initialize(this);
 
         HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
         allApps.freeze();
@@ -112,7 +113,7 @@
     @Test
     public void testShortcutIconWithTheme() throws Exception {
         setThemeEnabled(true);
-        AbstractLauncherUiTest.initialize(this);
+        initialize(this);
 
         HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
         allApps.freeze();
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index 3693163..2ce8eef 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 
 import org.junit.After;
 import org.junit.Before;
@@ -54,7 +55,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest {
+public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest<Launcher> {
 
     private AutoCloseable mLauncherLayout;
 
@@ -240,6 +241,7 @@
         });
     }
 
+    @ScreenRecordRule.ScreenRecord // b/329935119
     @Test
     @PortraitLandscape
     public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() {
@@ -349,7 +351,7 @@
         assertEquals("Existing page count does NOT match.", pageIds.length, pageCount);
         for (int i = 0; i < pageCount; i++) {
             CellLayout page = (CellLayout) launcher.getWorkspace().getPageAt(i);
-            int pageId = launcher.getWorkspace().getIdForScreen(page);
+            int pageId = launcher.getWorkspace().getCellLayoutId(page);
             assertEquals("The page's id at index " + i + " does NOT match.", pageId,
                     pageIds[i]);
         }
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
index 59c82a7..9afde0d 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.ui.workspace;
 
-import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
 import static com.android.launcher3.util.TestConstants.AppNames.CHROME_APP_NAME;
 
 import static org.junit.Assert.assertEquals;
@@ -23,8 +22,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import android.platform.test.annotations.PlatinumTest;
-
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.tapl.HomeAppIcon;
@@ -40,7 +37,7 @@
 /**
  * Test the basic interactions of the Workspace, adding pages, moving the pages and removing pages.
  */
-public class TaplWorkspaceTest extends AbstractLauncherUiTest {
+public class TaplWorkspaceTest extends AbstractLauncherUiTest<Launcher> {
 
     private AutoCloseable mLauncherLayout;
 
@@ -70,7 +67,6 @@
      * move between workspaces. After, make sure we can launch an app from the Workspace.
      * @throws Exception if we can't set the defaults icons that will appear at the beginning.
      */
-    @PlatinumTest(focusArea = "launcher")
     @Test
     public void testWorkspace() throws Exception {
         // Set workspace  that includes the chrome Activity app icon on the hotseat.
@@ -123,7 +119,6 @@
      * Similar to {@link TaplWorkspaceTest#testWorkspace} but here we also make sure we can delete
      * the pages.
      */
-    @PlatinumTest(focusArea = "launcher")
     @Test
     public void testAddAndDeletePageAndFling() {
         Workspace workspace = mLauncher.getWorkspace();
diff --git a/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
index 4770546..2294f5f 100644
--- a/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
+++ b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
@@ -39,6 +39,7 @@
         val config =
             Configuration(runningContext.resources.configuration).apply {
                 this.densityDpi = DisplayMetrics.DENSITY_DEFAULT
+                fontScale = 1.0f
             }
         context = runningContext.createConfigurationContext(config)
         iconSizeSteps = IconSizeSteps(context!!.resources)
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 8670d40..2e57ad5 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -45,6 +45,7 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.verify
@@ -95,8 +96,7 @@
         whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
 
         // Mock WindowManagerProxy
-        val displayInfo =
-            CachedDisplayInfo(Point(width, height), Surface.ROTATION_0, Rect(0, 0, 0, 0))
+        val displayInfo = CachedDisplayInfo(Point(width, height), Surface.ROTATION_0)
         whenever(windowManagerProxy.getDisplayInfo(any())).thenReturn(displayInfo)
         whenever(windowManagerProxy.estimateInternalDisplayBounds(any()))
             .thenAnswer(
@@ -124,6 +124,7 @@
         whenever(displayManager.getDisplay(any())).thenReturn(display)
 
         // Mock resources
+        doReturn(context).whenever(context).applicationContext
         whenever(resources.configuration).thenReturn(configuration)
         whenever(context.resources).thenReturn(resources)
 
@@ -135,8 +136,7 @@
     @Test
     @UiThreadTest
     fun testRotation() {
-        val displayInfo =
-            CachedDisplayInfo(Point(height, width), Surface.ROTATION_90, Rect(0, 0, 0, 0))
+        val displayInfo = CachedDisplayInfo(Point(height, width), Surface.ROTATION_90)
         whenever(windowManagerProxy.getDisplayInfo(any())).thenReturn(displayInfo)
         whenever(display.rotation).thenReturn(displayInfo.rotation)
         val configuration =
diff --git a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
new file mode 100644
index 0000000..dae09bb
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.LauncherApps
+import android.os.Bundle
+import android.os.Process
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.View.OnClickListener
+import android.view.View.OnFocusChangeListener
+import android.widget.FrameLayout
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.BubbleTextView
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
+import com.android.launcher3.apppairs.AppPairIcon
+import com.android.launcher3.folder.FolderIcon
+import com.android.launcher3.model.ModelWriter
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_UI_NOT_READY
+import com.android.launcher3.model.data.LauncherAppWidgetInfo.RESTORE_COMPLETED
+import com.android.launcher3.ui.TestViewHelpers
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR
+import com.android.launcher3.util.rule.ShellCommandRule
+import com.android.launcher3.widget.LauncherAppWidgetHostView
+import com.android.launcher3.widget.LauncherWidgetHolder
+import com.android.launcher3.widget.PendingAppWidgetHostView
+import com.android.launcher3.widget.WidgetManagerHelper
+import java.util.concurrent.Callable
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.any
+import org.mockito.kotlin.same
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+/** Tests for ItemInflater */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ItemInflaterTest {
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+    @get:Rule val grantWidgetRule = ShellCommandRule.grantWidgetBind()
+
+    private val clickListener = OnClickListener {}
+    private val focusListener = OnFocusChangeListener { _, _ -> }
+
+    @Mock private lateinit var modelWriter: ModelWriter
+
+    private lateinit var testContext: Context
+    private lateinit var uiContext: ActivityContextWrapper
+
+    private lateinit var widgetHolder: LauncherWidgetHolder
+    private lateinit var underTest: ItemInflater<*>
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testContext = InstrumentationRegistry.getInstrumentation().context
+
+        uiContext = ActivityContextWrapper(getApplicationContext())
+        uiContext.setTheme(Themes.getActivityThemeRes(uiContext, 0))
+
+        widgetHolder = LauncherWidgetHolder.newInstance(uiContext)
+        widgetHolder.startListening()
+        underTest =
+            ItemInflater(
+                uiContext,
+                widgetHolder,
+                clickListener,
+                focusListener,
+                FrameLayout(uiContext)
+            )
+    }
+
+    @After
+    fun tearDown() {
+        widgetHolder.destroy()
+    }
+
+    @Test
+    fun test_workspace_item_inflated_on_UI() {
+        val itemInfo = workspaceItemInfo()
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        assertTrue(view is BubbleTextView)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_workspace_item_inflated_on_BG() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+
+        val itemInfo = workspaceItemInfo()
+        val view =
+            VIEW_PREINFLATION_EXECUTOR.submit(
+                    Callable { underTest.inflateItem(itemInfo, modelWriter) }
+                )
+                .get()
+
+        assertTrue(view is BubbleTextView)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_folder_inflated_on_UI() {
+        val itemInfo = FolderInfo()
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        assertTrue(view is FolderIcon)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_folder_inflated_on_BG() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+
+        val itemInfo = FolderInfo()
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+
+        val view =
+            VIEW_PREINFLATION_EXECUTOR.submit(
+                    Callable { underTest.inflateItem(itemInfo, modelWriter) }
+                )
+                .get()
+
+        assertTrue(view is FolderIcon)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_app_pair_inflated_on_UI() {
+        val itemInfo = AppPairInfo()
+        itemInfo.itemType = ITEM_TYPE_APP_PAIR
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        assertTrue(view is AppPairIcon)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_app_pair_inflated_on_BG() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+
+        val itemInfo = AppPairInfo()
+        itemInfo.itemType = ITEM_TYPE_APP_PAIR
+        itemInfo.add(workspaceItemInfo())
+        itemInfo.add(workspaceItemInfo())
+
+        val view =
+            VIEW_PREINFLATION_EXECUTOR.submit(
+                    Callable { underTest.inflateItem(itemInfo, modelWriter) }
+                )
+                .get()
+
+        assertTrue(view is AppPairIcon)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_pending_widget_inflated_on_UI() {
+        val itemInfo = widgetItemInfo(true)
+
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        assertTrue(view is PendingAppWidgetHostView)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_pending_widget_inflated_on_BG() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+
+        val itemInfo = widgetItemInfo(true)
+        val view =
+            VIEW_PREINFLATION_EXECUTOR.submit(
+                    Callable { underTest.inflateItem(itemInfo, modelWriter) }
+                )
+                .get()
+
+        assertTrue(view is PendingAppWidgetHostView)
+        assertEquals(itemInfo, view!!.tag)
+    }
+
+    @Test
+    fun test_widget_restored_and_inflated_on_UI() {
+        val itemInfo = widgetItemInfo(false)
+
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        // Verify that the widget is automatically restored and a final widget is returned
+        assertTrue(view is LauncherAppWidgetHostView)
+        assertFalse(view is PendingAppWidgetHostView)
+        assertEquals(itemInfo, view!!.tag)
+        assertEquals(RESTORE_COMPLETED, itemInfo.restoreStatus)
+        verify(modelWriter).updateItemInDatabase(same(itemInfo))
+    }
+
+    @Test
+    fun test_widget_restored_and_inflated_on_BG() {
+        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
+        val itemInfo = widgetItemInfo(false)
+
+        val view =
+            VIEW_PREINFLATION_EXECUTOR.submit(
+                    Callable { underTest.inflateItem(itemInfo, modelWriter) }
+                )
+                .get()
+
+        // Verify that the widget is automatically restored and a final widget is returned
+        assertTrue(view is LauncherAppWidgetHostView)
+        assertFalse(view is PendingAppWidgetHostView)
+        assertEquals(itemInfo, view!!.tag)
+        assertEquals(RESTORE_COMPLETED, itemInfo.restoreStatus)
+        verify(modelWriter).updateItemInDatabase(same(itemInfo))
+    }
+
+    @Test
+    fun test_invalid_widget_deleted() {
+        val itemInfo =
+            widgetItemInfo(false).apply {
+                providerName = ComponentName(providerName.packageName, "invalid_provider_name")
+            }
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+        assertNull(view)
+        verify(modelWriter).deleteItemFromDatabase(same(itemInfo), any())
+    }
+
+    @Test
+    fun test_normal_widget_inflated_UI() {
+        val providerInfo = TestViewHelpers.findWidgetProvider(false)
+        val id = widgetHolder.allocateAppWidgetId()
+        assertTrue(
+            WidgetManagerHelper(uiContext).bindAppWidgetIdIfAllowed(id, providerInfo, Bundle())
+        )
+        val itemInfo = LauncherAppWidgetInfo(id, providerInfo.provider)
+        itemInfo.spanX = 2
+        itemInfo.spanY = 2
+
+        val view =
+            MAIN_EXECUTOR.submit(Callable { underTest.inflateItem(itemInfo, modelWriter) }).get()
+
+        // Verify that the widget is automatically restored and a final widget is returned
+        assertTrue(view is LauncherAppWidgetHostView)
+        assertFalse(view is PendingAppWidgetHostView)
+        assertEquals(itemInfo, view!!.tag)
+        verifyNoMoreInteractions(modelWriter)
+    }
+
+    private fun workspaceItemInfo() =
+        AppInfo(
+                uiContext,
+                uiContext
+                    .getSystemService(LauncherApps::class.java)!!
+                    .getActivityList(testContext.packageName, Process.myUserHandle())[0],
+                Process.myUserHandle()
+            )
+            .makeWorkspaceItem(uiContext)
+
+    private fun widgetItemInfo(hasConfig: Boolean) =
+        LauncherAppWidgetInfo(0, TestViewHelpers.findWidgetProvider(hasConfig).component).apply {
+            spanX = 2
+            spanY = 2
+            restoreStatus = FLAG_ID_NOT_VALID or FLAG_UI_NOT_READY
+        }
+}
diff --git a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
deleted file mode 100644
index 61ec669..0000000
--- a/tests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.android.launcher3.util
-
-import com.android.launcher3.LauncherModel
-import com.android.launcher3.model.BgDataModel
-
-object ModelTestExtensions {
-    /** Clears and reloads Launcher db to cleanup the workspace */
-    fun LauncherModel.clearModelDb() {
-        // Load the model once so that there is no pending migration:
-        loadModelSync()
-        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
-            modelDbController.run {
-                tryMigrateDB()
-                createEmptyDB()
-                clearEmptyDbFlag()
-            }
-        }
-        // Reload model
-        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { forceReload() }
-        loadModelSync()
-    }
-
-    fun LauncherModel.loadModelSync() {
-        val mockCb: BgDataModel.Callbacks = object : BgDataModel.Callbacks {}
-        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { addCallbacksAndLoad(mockCb) }
-        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {}
-        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) {}
-        TestUtil.runOnExecutorSync(Executors.MAIN_EXECUTOR) { removeCallbacks(mockCb) }
-    }
-}
diff --git a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
new file mode 100644
index 0000000..d1da5f4
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util;
+
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+/** Unit tests for {@link PackageManagerHelper}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class PackageManagerHelperTest {
+    @Rule
+    public ExpectedException exception = ExpectedException.none();
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    private static final String TEST_PACKAGE = "com.android.test.package";
+    private static final int TEST_USER = 2;
+
+    private Context mContext;
+    private LauncherApps mLauncherApps;
+    private PackageManagerHelper mPackageManagerHelper;
+
+    @Before
+    public void setup() {
+        mContext = mock(Context.class);
+        mLauncherApps = mock(LauncherApps.class);
+        when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps);
+        mPackageManagerHelper = new PackageManagerHelper(mContext);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    public void getApplicationInfo_archivedApp_appInfoIsNotNull()
+            throws PackageManager.NameNotFoundException {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.isArchived = true;
+        when(mLauncherApps.getApplicationInfo(TEST_PACKAGE, 0 /* flags */,
+                UserHandle.of(TEST_USER)))
+                .thenReturn(applicationInfo);
+
+        assertThat(mPackageManagerHelper.getApplicationInfo(TEST_PACKAGE, UserHandle.of(TEST_USER),
+                0 /* flags */))
+                .isNotNull();
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/TestConstants.java b/tests/src/com/android/launcher3/util/TestConstants.java
index 6f3c63a..bf5ccd0 100644
--- a/tests/src/com/android/launcher3/util/TestConstants.java
+++ b/tests/src/com/android/launcher3/util/TestConstants.java
@@ -23,6 +23,7 @@
         public static final String MAPS_APP_NAME = "Maps";
         public static final String STORE_APP_NAME = "Play Store";
         public static final String GMAIL_APP_NAME = "Gmail";
+        public static final String PHOTOS_APP_NAME = "Photos";
         public static final String CHROME_APP_NAME = "Chrome";
         public static final String MESSAGES_APP_NAME = "Messages";
     }
diff --git a/tests/src/com/android/launcher3/util/rule/ExtendedLongPressTimeoutRule.java b/tests/src/com/android/launcher3/util/rule/ExtendedLongPressTimeoutRule.java
new file mode 100644
index 0000000..702988c
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/ExtendedLongPressTimeoutRule.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.ViewConfiguration;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class ExtendedLongPressTimeoutRule implements TestRule {
+
+    private static final String TAG = "ExtendedLongPressTimeoutRule";
+
+    private static final float LONG_PRESS_TIMEOUT_MULTIPLIER = 10f;
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                ContentResolver contentResolver = InstrumentationRegistry.getInstrumentation()
+                        .getContext()
+                        .getContentResolver();
+                int prevLongPressTimeout = Settings.Secure.getInt(
+                        contentResolver,
+                        Settings.Secure.LONG_PRESS_TIMEOUT,
+                        ViewConfiguration.getLongPressTimeout());
+                int newLongPressTimeout =
+                        (int) (prevLongPressTimeout * LONG_PRESS_TIMEOUT_MULTIPLIER);
+
+                try {
+                    Log.d(TAG, "In try-block: Setting long press timeout from "
+                            + prevLongPressTimeout + "ms to " + newLongPressTimeout + "ms");
+                    Settings.Secure.putInt(
+                            contentResolver,
+                            Settings.Secure.LONG_PRESS_TIMEOUT,
+                            (int) (prevLongPressTimeout * LONG_PRESS_TIMEOUT_MULTIPLIER));
+
+                    base.evaluate();
+                } catch (Exception e) {
+                    Log.e(TAG, "Error", e);
+                    throw e;
+                } finally {
+                    Log.d(TAG, "In finally-block: resetting long press timeout to "
+                            + prevLongPressTimeout + "ms");
+                    Settings.Secure.putInt(
+                            contentResolver,
+                            Settings.Secure.LONG_PRESS_TIMEOUT,
+                            prevLongPressTimeout);
+                }
+            }
+        };
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 10b428a..7fba33e 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -125,8 +125,6 @@
             Log.e(TAG, "Failed to save accessibility hierarchy", ex);
         }
 
-        dumpCommand("logcat -d -s TestRunner", diagFile(description, "FilteredLogcat", "txt"));
-
         // Dump bugreport
         if (!sSavedBugreport) {
             dumpCommand("bugreportz -s", diagFile(description, "Bugreport", "zip"));
diff --git a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
index 7a5cf2c..ff96afb 100644
--- a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
@@ -49,6 +49,9 @@
             return base;
         }
 
+        final Boolean keepRecordOnSuccess = description.getAnnotation(KeepRecordOnSuccess.class)
+                != null;
+
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
@@ -70,7 +73,7 @@
                     device.executeShellCommand("kill -INT " + screenRecordPid);
                     Log.e(TAG, "Screenrecord captured at: " + outputFile);
                     output.close();
-                    if (success) {
+                    if (success && !keepRecordOnSuccess) {
                         automation.executeShellCommand("rm " + outputFile);
                     }
                 }
@@ -85,4 +88,14 @@
     @Target(ElementType.METHOD)
     public @interface ScreenRecord {
     }
+
+
+    /**
+     * Interface to indicate that we should keep the screen record even if the test succeeds, use
+     * sparingly since it uses a lof of memory.
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    public @interface KeepRecordOnSuccess {
+    }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/SetPropRule.java b/tests/src/com/android/launcher3/util/rule/SetPropRule.java
new file mode 100644
index 0000000..74fec35
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/SetPropRule.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiDevice;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Test rule which executes a set prop command at the start of the test.
+ * This rule needs the property tag and property value so that value can be set to a tag.
+ */
+public class SetPropRule implements TestRule {
+    private static final String SETPROP_PREFIX = "setprop";
+    private static final String GETPROP_PREFIX = "getprop";
+    private static final String UNKNOWN = "UNKNOWN";
+    @NonNull private final String mPropTag;
+    @NonNull private final String mPropValue;
+
+    public SetPropRule(@NonNull String propTag, @NonNull String propValue) {
+        mPropTag = propTag.trim();
+        mPropValue = propValue.trim();
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                String getpropCmd = GETPROP_PREFIX + " " + mPropTag;
+                String initialValue = UiDevice.getInstance(getInstrumentation())
+                        .executeShellCommand(getpropCmd);
+                if (TextUtils.isEmpty(initialValue.trim())) {
+                    initialValue = UNKNOWN;
+                }
+                // setprop command always follows format : setprop <TAG> <value>
+                String revertSetPropCmd = SETPROP_PREFIX + " " + mPropTag + " " + initialValue;
+                String setPropCmd = SETPROP_PREFIX + " " + mPropTag + " " + mPropValue;
+                new ShellCommandRule(setPropCmd, revertSetPropCmd)
+                        .apply(base, description).evaluate();
+            }
+        };
+    }
+
+    /**
+     * Enables "InputTransportPublisher" debug flag. This prints the key input events dispatched by
+     * the system server.
+     * adb shell setprop log.tag.InputTransportPublisher DEBUG
+     * See {@link com.android.cts.input.DebugInputRule} for more details.
+     */
+    public static SetPropRule createEnableInputTransportPublisherRule() {
+        return new SetPropRule("log.tag.InputTransportPublisher", "DEBUG");
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index 08953fc..2219003 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3.util.rule;
 
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
 
@@ -39,7 +39,6 @@
  * Test rule which executes a shell command at the start of the test.
  */
 public class ShellCommandRule implements TestRule {
-
     private final String mCmd;
     private final String mRevertCommand;
     private final boolean mCheckSuccess;
@@ -75,8 +74,7 @@
                 } finally {
                     if (mRevertCommand != null) {
                         final String revertResult = UiDevice.getInstance(
-                                getInstrumentation()).executeShellCommand(
-                                mRevertCommand);
+                                getInstrumentation()).executeShellCommand(mRevertCommand);
                         if (mCheckSuccess) {
                             Assert.assertTrue(
                                     "Failed command: " + mRevertCommand
diff --git a/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java b/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java
deleted file mode 100644
index 6b91474..0000000
--- a/tests/src/com/android/launcher3/util/rule/StaticMockitoRule.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.util.rule;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-
-import org.junit.rules.MethodRule;
-import org.junit.runners.model.FrameworkMethod;
-import org.junit.runners.model.Statement;
-import org.mockito.junit.MockitoRule;
-import org.mockito.quality.Strictness;
-
-/**
- * Similar to {@link MockitoRule}, but uses {@link StaticMockitoSession}, which allows mocking
- * static methods.
- */
-public class StaticMockitoRule implements MethodRule {
-    private Class<?>[] mClasses;
-
-    public StaticMockitoRule(Class<?>... classes) {
-        mClasses = classes;
-    }
-
-    @Override
-    public Statement apply(Statement base, FrameworkMethod method, Object target) {
-        return new Statement() {
-            public void evaluate() throws Throwable {
-                StaticMockitoSessionBuilder builder =
-                        mockitoSession()
-                                .name(target.getClass().getSimpleName() + "." + method.getName())
-                                .initMocks(target)
-                                .strictness(Strictness.STRICT_STUBS);
-
-                for (Class<?> clazz : mClasses) {
-                    builder.mockStatic(clazz);
-                }
-
-                StaticMockitoSession session = builder.startMocking();
-                Throwable testFailure = evaluateSafely(base);
-                session.finishMocking(testFailure);
-                if (testFailure != null) {
-                    throw testFailure;
-                }
-            }
-
-            private Throwable evaluateSafely(Statement base) {
-                try {
-                    base.evaluate();
-                    return null;
-                } catch (Throwable throwable) {
-                    return throwable;
-                }
-            }
-        };
-    }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
new file mode 100644
index 0000000..d3516d1
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util.rule
+
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/** Copy a file from the tests assets folder to the phone. */
+class TestToPhoneFileCopier(
+    val src: String,
+    dest: String,
+    private val removeOnFinish: Boolean = false
+) : TestRule {
+
+    private val dstFile =
+        File(InstrumentationRegistry.getInstrumentation().targetContext.dataDir, dest)
+
+    fun getDst() = dstFile.absolutePath
+
+    fun before() =
+        dstFile.writeBytes(
+            InstrumentationRegistry.getInstrumentation().context.assets.open(src).readBytes()
+        )
+
+    fun after() {
+        if (removeOnFinish) {
+            dstFile.delete()
+        }
+    }
+
+    override fun apply(base: Statement, description: Description): Statement =
+        object : Statement() {
+            override fun evaluate() {
+                before()
+                try {
+                    base.evaluate()
+                } finally {
+                    after()
+                }
+            }
+        }
+}
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
new file mode 100644
index 0000000..460058b
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -0,0 +1,162 @@
+package com.android.launcher3.widget
+
+import android.appwidget.AppWidgetProviderInfo
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.view.ContextThemeWrapper
+import android.view.LayoutInflater
+import android.widget.RemoteViews
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.IconProvider
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GeneratedPreviewTest {
+    @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+    private val providerName =
+        ComponentName(
+            "com.android.launcher3.tests",
+            "com.android.launcher3.testcomponent.AppWidgetNoConfig"
+        )
+    private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue
+    private lateinit var context: Context
+    private lateinit var generatedPreview: RemoteViews
+    private lateinit var widgetCell: WidgetCell
+    private lateinit var helper: WidgetManagerHelper
+    private lateinit var appWidgetProviderInfo: LauncherAppWidgetProviderInfo
+    private lateinit var widgetItem: WidgetItem
+
+    @Before
+    fun setup() {
+        context = getApplicationContext()
+        generatedPreview = RemoteViews(context.packageName, generatedPreviewLayout)
+        widgetCell =
+            LayoutInflater.from(
+                    ActivityContextWrapper(
+                        ContextThemeWrapper(
+                            context,
+                            com.android.launcher3.R.style.WidgetContainerTheme
+                        )
+                    )
+                )
+                .inflate(com.android.launcher3.R.layout.widget_cell, null) as WidgetCell
+        appWidgetProviderInfo =
+            AppWidgetProviderInfo()
+                .apply {
+                    generatedPreviewCategories = WIDGET_CATEGORY_HOME_SCREEN
+                    provider = providerName
+                    providerInfo = ActivityInfo().apply { applicationInfo = ApplicationInfo() }
+                }
+                .let { LauncherAppWidgetProviderInfo.fromProviderInfo(context, it) }
+        helper =
+            object : WidgetManagerHelper(context) {
+                override fun loadGeneratedPreview(
+                    info: AppWidgetProviderInfo,
+                    widgetCategory: Int
+                ) =
+                    generatedPreview.takeIf {
+                        info === appWidgetProviderInfo &&
+                            widgetCategory == WIDGET_CATEGORY_HOME_SCREEN
+                    }
+            }
+        createWidgetItem()
+    }
+
+    private fun createWidgetItem() {
+        Executors.MODEL_EXECUTOR.submit {
+                val idp = InvariantDeviceProfile()
+                widgetItem =
+                    WidgetItem(
+                        appWidgetProviderInfo,
+                        idp,
+                        IconCache(context, idp, null, IconProvider(context)),
+                        context,
+                        helper,
+                    )
+            }
+            .get()
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview() {
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview_noPreview() {
+        appWidgetProviderInfo.generatedPreviewCategories = 0
+        createWidgetItem()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview_nullPreview() {
+        appWidgetProviderInfo.generatedPreviewCategories =
+            WIDGET_CATEGORY_HOME_SCREEN or WIDGET_CATEGORY_KEYGUARD
+        createWidgetItem()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
+        // loadGeneratedPreview returns null for KEYGUARD, so this should still be false.
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview_flagDisabled() {
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_getGeneratedPreview() {
+        val preview = widgetItem.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN)
+        assertThat(preview).isEqualTo(generatedPreview)
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetCell_showGeneratedPreview() {
+        widgetCell.applyFromCellItem(widgetItem)
+        assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
+        assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
+            .isEqualTo(appWidgetProviderInfo)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetCell_showGeneratedPreview_flagDisabled() {
+        widgetCell.applyFromCellItem(widgetItem)
+        assertThat(widgetCell.appWidgetHostViewPreview).isNull()
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt b/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt
new file mode 100644
index 0000000..6e751e0
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker
+
+import android.content.Context
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.widget.WidgetImageView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class WidgetImageViewTest {
+    private lateinit var context: Context
+    private lateinit var widgetImageView: WidgetImageView
+
+    @Mock private lateinit var testDrawable: Drawable
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+        widgetImageView = spy(WidgetImageView(context))
+    }
+
+    @Test
+    fun getBitmapBounds_aspectRatioLargerThanView_scaledByWidth() {
+        // view - 100 x 100
+        whenever(widgetImageView.width).thenReturn(100)
+        whenever(widgetImageView.height).thenReturn(100)
+        // bitmap - 200 x 100
+        whenever(testDrawable.intrinsicWidth).thenReturn(200)
+        whenever(testDrawable.intrinsicHeight).thenReturn(100)
+
+        widgetImageView.drawable = testDrawable
+        val bitmapBounds = widgetImageView.bitmapBounds
+
+        // new scaled width of bitmap is = 100, and height is scaled to 1/2 = 50
+        assertThat(bitmapBounds).isEqualTo(Rect(0, 25, 100, 75))
+    }
+
+    @Test
+    fun getBitmapBounds_aspectRatioSmallerThanView_scaledByHeight() {
+        // view - 100 x 100
+        whenever(widgetImageView.width).thenReturn(100)
+        whenever(widgetImageView.height).thenReturn(100)
+        // bitmap - 100 x 200
+        whenever(testDrawable.intrinsicWidth).thenReturn(100)
+        whenever(testDrawable.intrinsicHeight).thenReturn(200)
+        widgetImageView.drawable = testDrawable
+
+        val bitmapBounds = widgetImageView.bitmapBounds
+
+        // new scaled height of bitmap is = 100, and width is scaled to 1/2 = 50
+        assertThat(bitmapBounds).isEqualTo(Rect(25, 0, 75, 100))
+    }
+
+    @Test
+    fun getBitmapBounds_noScale_returnsOriginalDrawableBounds() {
+        // view - 200 x 100
+        whenever(widgetImageView.width).thenReturn(200)
+        whenever(widgetImageView.height).thenReturn(100)
+        // bitmap - 200 x 100
+        whenever(testDrawable.intrinsicWidth).thenReturn(200)
+        whenever(testDrawable.intrinsicHeight).thenReturn(100)
+
+        widgetImageView.drawable = testDrawable
+        val bitmapBounds = widgetImageView.bitmapBounds
+
+        // no scaling
+        assertThat(bitmapBounds).isEqualTo(Rect(0, 0, 200, 100))
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
new file mode 100644
index 0000000..60a4cd3
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import static android.content.pm.ApplicationInfo.CATEGORY_AUDIO;
+import static android.content.pm.ApplicationInfo.CATEGORY_IMAGE;
+import static android.content.pm.ApplicationInfo.CATEGORY_NEWS;
+import static android.content.pm.ApplicationInfo.CATEGORY_PRODUCTIVITY;
+import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
+import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED;
+import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO;
+import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.os.Process;
+
+import androidx.test.core.content.pm.ApplicationInfoBuilder;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Map;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WidgetRecommendationCategoryProviderTest {
+    private static final String TEST_PACKAGE = "com.foo.test";
+    private static final String TEST_APP_NAME = "foo";
+    private static final WidgetRecommendationCategory PRODUCTIVITY =
+            new WidgetRecommendationCategory(
+                    R.string.productivity_widget_recommendation_category_label,
+                    /*order=*/0);
+    private static final WidgetRecommendationCategory NEWS =
+            new WidgetRecommendationCategory(
+                    R.string.news_widget_recommendation_category_label, /*order=*/1);
+    private static final WidgetRecommendationCategory SUGGESTED_FOR_YOU =
+            new WidgetRecommendationCategory(
+                    R.string.others_widget_recommendation_category_label, /*order=*/4);
+    private static final WidgetRecommendationCategory SOCIAL =
+            new WidgetRecommendationCategory(
+                    R.string.social_widget_recommendation_category_label,
+                    /*order=*/5);
+    private static final WidgetRecommendationCategory ENTERTAINMENT =
+            new WidgetRecommendationCategory(
+                    R.string.entertainment_widget_recommendation_category_label,
+                    /*order=*/6);
+
+    private final ApplicationInfo mTestAppInfo = ApplicationInfoBuilder.newBuilder().setPackageName(
+            TEST_PACKAGE).setName(TEST_APP_NAME).build();
+    private Context mContext;
+    @Mock
+    private IconCache mIconCache;
+
+    private WidgetItem mTestWidgetItem;
+    @Mock
+    private LauncherApps mLauncherApps;
+    private InvariantDeviceProfile mTestProfile;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
+            @Override
+            public Object getSystemService(String name) {
+                return LAUNCHER_APPS_SERVICE.equals(name) ? mLauncherApps : super.getSystemService(
+                        name);
+            }
+        };
+        mTestAppInfo.flags = FLAG_INSTALLED;
+        mTestProfile = new InvariantDeviceProfile();
+        mTestProfile.numRows = 5;
+        mTestProfile.numColumns = 5;
+        createTestWidgetItem();
+    }
+
+    @Test
+    public void getWidgetRecommendationCategory_returnsMappedCategory() throws Exception {
+        ImmutableMap<Integer, WidgetRecommendationCategory> testCategories = ImmutableMap.of(
+                CATEGORY_PRODUCTIVITY, PRODUCTIVITY,
+                CATEGORY_NEWS, NEWS,
+                CATEGORY_SOCIAL, SOCIAL,
+                CATEGORY_AUDIO, ENTERTAINMENT,
+                CATEGORY_IMAGE, ENTERTAINMENT,
+                CATEGORY_VIDEO, ENTERTAINMENT,
+                CATEGORY_UNDEFINED, SUGGESTED_FOR_YOU);
+
+        for (Map.Entry<Integer, WidgetRecommendationCategory> testCategory :
+                testCategories.entrySet()) {
+
+            mTestAppInfo.category = testCategory.getKey();
+            when(mLauncherApps.getApplicationInfo(/*packageName=*/ eq(TEST_PACKAGE),
+                    /*flags=*/ eq(0),
+                    /*user=*/ eq(Process.myUserHandle())))
+                    .thenReturn(mTestAppInfo);
+
+            WidgetRecommendationCategory category = Executors.MODEL_EXECUTOR.submit(() ->
+                    new WidgetRecommendationCategoryProvider().getWidgetRecommendationCategory(
+                            mContext,
+                            mTestWidgetItem)).get();
+
+            assertThat(category).isEqualTo(testCategory.getValue());
+        }
+    }
+
+    private void createTestWidgetItem() {
+        String widgetLabel = "Foo Widget";
+        String widgetClassName = ".mWidget";
+
+        doAnswer(invocation -> widgetLabel).when(mIconCache).getTitleNoCache(any());
+
+        AppWidgetProviderInfo providerInfo = AppWidgetManager.getInstance(getApplicationContext())
+                .getInstalledProvidersForPackage(
+                        getInstrumentation().getContext().getPackageName(), Process.myUserHandle())
+                .get(0);
+        providerInfo.provider = ComponentName.createRelative(TEST_PACKAGE, widgetClassName);
+
+        LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
+                LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, providerInfo);
+        launcherAppWidgetProviderInfo.spanX = 2;
+        launcherAppWidgetProviderInfo.spanY = 2;
+        launcherAppWidgetProviderInfo.label = widgetLabel;
+        mTestWidgetItem = new WidgetItem(launcherAppWidgetProviderInfo, mTestProfile, mIconCache,
+                mContext
+        );
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderAccessibilityTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderAccessibilityTest.java
new file mode 100644
index 0000000..b347f07
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderAccessibilityTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.ActivityContextWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class WidgetsListHeaderAccessibilityTest {
+    private Context mContext;
+    private LayoutInflater mLayoutInflater;
+    @Mock
+    private View.OnClickListener mOnClickListener;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = new ActivityContextWrapper(getApplicationContext());
+        mLayoutInflater = LayoutInflater.from(
+                new ContextThemeWrapper(mContext, R.style.WidgetContainerTheme));
+    }
+
+    @Test
+    public void singlePaneCollapsable_hasCustomAccessibilityActions() {
+        WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
+                R.layout.widgets_list_row_header,
+                new FrameLayout(mContext), false);
+
+        assertThat(header.getAccessibilityDelegate()).isNotNull();
+
+        header.setOnClickListener(mOnClickListener);
+        header.getAccessibilityDelegate().performAccessibilityAction(header,
+                AccessibilityNodeInfo.ACTION_EXPAND, null);
+        header.getAccessibilityDelegate().performAccessibilityAction(header,
+                AccessibilityNodeInfo.ACTION_COLLAPSE, null);
+
+        verify(mOnClickListener, times(2)).onClick(header);
+    }
+
+    @Test
+    public void twoPaneNonCollapsable_noCustomAccessibilityDelegate() {
+        WidgetsListHeader header = (WidgetsListHeader) mLayoutInflater.inflate(
+                R.layout.widgets_list_row_header_two_pane,
+                new FrameLayout(mContext), false);
+
+        assertThat(header.getAccessibilityDelegate()).isNull();
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 60590e7..85fb380 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.os.UserHandle;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -52,6 +53,7 @@
 import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetManagerHelper;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 
 import org.junit.Before;
@@ -95,7 +97,8 @@
 
         mViewHolderBinder = new WidgetsListTableViewHolderBinder(
                 mContext,
-                LayoutInflater.from(mContext),
+                LayoutInflater.from(new ContextThemeWrapper(mContext,
+                        com.android.launcher3.R.style.WidgetContainerTheme)),
                 mOnIconClickListener,
                 mOnLongClickListener);
     }
@@ -137,6 +140,7 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+        WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
@@ -144,7 +148,7 @@
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
-                    mTestProfile, mIconCache, mContext));
+                    mTestProfile, mIconCache, mContext, widgetManager));
         }
         return widgetItems;
     }
diff --git a/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt b/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
new file mode 100644
index 0000000..040fbf5
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.Point
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+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.WidgetItem
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WidgetPreviewContainerSizesTest {
+    private lateinit var context: Context
+    private lateinit var deviceProfile: DeviceProfile
+    private lateinit var testInvariantProfile: InvariantDeviceProfile
+
+    @Mock private lateinit var iconCache: IconCache
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+        testInvariantProfile = LauncherAppState.getIDP(context)
+        deviceProfile = testInvariantProfile.getDeviceProfile(context).copy(context)
+    }
+
+    @Test
+    fun widgetPreviewContainerSize_forItem_returnsCorrectContainerSize() {
+        val testSizes = getTestSizes(deviceProfile)
+        val expectedPreviewContainers = testSizes.values.toList()
+
+        for ((index, widgetSize) in testSizes.keys.withIndex()) {
+            val widgetItem = createWidgetItem(widgetSize, context, testInvariantProfile, iconCache)
+
+            assertWithMessage("size for $widgetSize should be: ${expectedPreviewContainers[index]}")
+                .that(WidgetPreviewContainerSize.forItem(widgetItem, deviceProfile))
+                .isEqualTo(expectedPreviewContainers[index])
+        }
+    }
+
+    companion object {
+        private const val TEST_PACKAGE = "com.google.test"
+
+        private val HANDHELD_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
+            mapOf(
+                // 1x1
+                Point(1, 1) to WidgetPreviewContainerSize(1, 1),
+                // 2x1
+                Point(2, 1) to WidgetPreviewContainerSize(2, 1),
+                Point(3, 1) to WidgetPreviewContainerSize(2, 1),
+                // 4x1
+                Point(4, 1) to WidgetPreviewContainerSize(4, 1),
+                // 2x2
+                Point(2, 2) to WidgetPreviewContainerSize(2, 2),
+                Point(3, 3) to WidgetPreviewContainerSize(2, 2),
+                Point(3, 2) to WidgetPreviewContainerSize(2, 2),
+                // 2x3
+                Point(2, 3) to WidgetPreviewContainerSize(2, 3),
+                Point(3, 4) to WidgetPreviewContainerSize(2, 3),
+                Point(3, 5) to WidgetPreviewContainerSize(2, 3),
+                // 4x2
+                Point(4, 2) to WidgetPreviewContainerSize(4, 2),
+                // 4x3
+                Point(4, 3) to WidgetPreviewContainerSize(4, 3),
+                Point(4, 4) to WidgetPreviewContainerSize(4, 3),
+            )
+
+        private val TABLET_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
+            mapOf(
+                // 1x1
+                Point(1, 1) to WidgetPreviewContainerSize(1, 1),
+                // 2x1
+                Point(2, 1) to WidgetPreviewContainerSize(2, 1),
+                // 3x1
+                Point(3, 1) to WidgetPreviewContainerSize(3, 1),
+                Point(4, 1) to WidgetPreviewContainerSize(3, 1),
+                // 2x2
+                Point(2, 2) to WidgetPreviewContainerSize(2, 2),
+                // 2x3
+                Point(2, 3) to WidgetPreviewContainerSize(2, 3),
+                // 3x2
+                Point(3, 2) to WidgetPreviewContainerSize(3, 2),
+                Point(4, 2) to WidgetPreviewContainerSize(3, 2),
+                Point(5, 2) to WidgetPreviewContainerSize(3, 2),
+                // 3x3
+                Point(3, 3) to WidgetPreviewContainerSize(3, 3),
+                Point(4, 4) to WidgetPreviewContainerSize(3, 3),
+                // 3x4
+                Point(5, 4) to WidgetPreviewContainerSize(3, 4),
+                Point(3, 4) to WidgetPreviewContainerSize(3, 4),
+                Point(5, 5) to WidgetPreviewContainerSize(3, 4),
+                Point(6, 4) to WidgetPreviewContainerSize(3, 4),
+                Point(6, 5) to WidgetPreviewContainerSize(3, 4),
+            )
+
+        private fun getTestSizes(dp: DeviceProfile) =
+            if (dp.isTablet && !dp.isTwoPanels) {
+                TABLET_TEST_SIZES
+            } else {
+                HANDHELD_TEST_SIZES
+            }
+
+        private fun createWidgetItem(
+            widgetSize: Point,
+            context: Context,
+            invariantDeviceProfile: InvariantDeviceProfile,
+            iconCache: IconCache
+        ): WidgetItem {
+            val providerInfo =
+                createAppWidgetProviderInfo(
+                    ComponentName.createRelative(
+                        TEST_PACKAGE,
+                        /*cls=*/ ".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y
+                    )
+                )
+            val widgetInfo =
+                LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo).apply {
+                    spanX = widgetSize.x
+                    spanY = widgetSize.y
+                }
+            return WidgetItem(widgetInfo, invariantDeviceProfile, iconCache, context)
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
index 2c5a396..b2cb266 100644
--- a/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
@@ -63,6 +63,7 @@
     private static final String TEST_PACKAGE = "com.google.test";
 
     private static final int SPACE_SIZE = 10;
+    // Note - actual widget size includes SPACE_SIZE (border) + cell padding.
     private static final int CELL_SIZE = 50;
     private static final int NUM_OF_COLS = 5;
     private static final int NUM_OF_ROWS = 5;
@@ -105,7 +106,7 @@
 
 
     @Test
-    public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding0_shouldGroupWidgetsInTable() {
+    public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding0() {
         List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
                 mWidget2x2);
 
@@ -113,17 +114,20 @@
                 WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
                         mTestDeviceProfile, 220, 0);
 
-        // Row 0: 1x1(50px), 2x2(110px)
-        // Row 1: 2x3(110px), 2x4(110px)
-        // Row 2: 4x4(230px)
-        assertThat(widgetItemInTable).hasSize(3);
-        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2);
-        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget2x4);
-        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
+        // With reordering, rows displayed in order of increasing size.
+        // Row 0: 1x1(50px)
+        // Row 1: 2x2(in a 2x2 container - 110px)
+        // Row 2: 2x3(in a 2x3 container - 110px), 2x4(in a 2x3 container - 110px)
+        // Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+        assertThat(widgetItemInTable).hasSize(4);
+        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+        assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
     }
 
     @Test
-    public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding10_shouldGroupWidgetsInTable() {
+    public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding10() {
         List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
                 mWidget2x2);
 
@@ -131,9 +135,13 @@
                 WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
                         mTestDeviceProfile, 220, 10);
 
-        // Row 0: 1x1(50px), 2x2(110px)
-        // Row 1: 2x3(110px), 2x4(110px)
-        // Row 2: 4x4(230px)
+        // With reordering, but space taken up by cell padding, so, no grouping (even if 2x2 and 2x3
+        // use same preview container).
+        // Row 0: 1x1(50px)
+        // Row 1: 2x2(in a 2x2 container: 130px)
+        // Row 2: 2x3(in a 2x3 container: 130px)
+        // Row 3: 2x4(in a 2x3 container: 130px)
+        // Row 4: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
         assertThat(widgetItemInTable).hasSize(5);
         assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
         assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
@@ -143,7 +151,29 @@
     }
 
     @Test
-    public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow350_cellPadding0_shouldGroupWidgetsInTable() {
+    public void groupWithReordering_widgetsOnly_maxSpanPxPerRow260_cellPadding10() {
+        List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
+                mWidget2x2);
+
+        List<ArrayList<WidgetItem>> widgetItemInTable =
+                WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
+                        mTestDeviceProfile, 260, 10);
+
+        // With reordering, even with cellPadding, enough space to group 2x3 and 2x4 (which also use
+        // same container)
+        // Row 0: 1x1(50px)
+        // Row 1: 2x2(in a 2x2 container: 130px)
+        // Row 2: 2x3(in a 2x3 container: 130px), 2x4(in a 2x3 container: 130px)
+        // Row 3: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
+        assertThat(widgetItemInTable).hasSize(4);
+        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+        assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
+    }
+
+    @Test
+    public void groupWithReordering_widgetsOnly_maxSpanPxPerRow350_cellPadding0() {
         List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
                 mWidget2x2);
 
@@ -151,17 +181,20 @@
                 WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
                         mTestDeviceProfile, 350, 0);
 
-        // Row 0: 1x1(50px), 2x2(110px), 2x3(110px)
-        // Row 1: 2x4(110px)
-        // Row 2: 4x4(230px)
-        assertThat(widgetItemInTable).hasSize(3);
-        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2, mWidget2x3);
-        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x4);
-        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
+        // With reordering, rows displayed in order of increasing size.
+        // Row 0: 1x1(50px)
+        // Row 1: 2x2(in a 2x2 container: 110px)
+        // Row 2: 2x3(in a 2x3 container: 110px), 2x4(in a 2x3 container: 110px)
+        // Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+        assertThat(widgetItemInTable).hasSize(4);
+        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+        assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
     }
 
     @Test
-    public void groupWidgetItemsIntoTableWithReordering_mixItems_maxSpanPxPerRow350_cellPadding0_shouldGroupWidgetsInTable() {
+    public void groupWithReordering_mixItems_maxSpanPxPerRow350_cellPadding0() {
         List<WidgetItem> widgetItems = List.of(mWidget4x4, mShortcut3, mWidget2x3, mShortcut1,
                 mWidget1x1, mShortcut2, mWidget2x4, mWidget2x2);
 
@@ -169,19 +202,22 @@
                 WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
                         mTestDeviceProfile, 350, 0);
 
-        // Row 0: 1x1(50px), 2x2(110px), 2x3(110px)
-        // Row 1: 2x4(110px),
-        // Row 2: 4x4(230px)
-        // Row 3: shortcut3(50px), shortcut1(50px), shortcut2(50px)
-        assertThat(widgetItemInTable).hasSize(4);
-        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2, mWidget2x3);
-        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x4);
-        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
-        assertThat(widgetItemInTable.get(3)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
+        // With reordering - rows displays in order of increasing size:
+        // Row 0: 1x1(50px)
+        // Row 1: 2x2(110px)
+        // Row 2: 2x3 (in a 2x3 container 110px), 2x4 (in a 2x3 container 110px)
+        // Row 3: 4x4 (in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+        // Row 4: shortcut3, shortcut1, shortcut2 (shortcuts are always displayed at bottom)
+        assertThat(widgetItemInTable).hasSize(5);
+        assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+        assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
+        assertThat(widgetItemInTable.get(4)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
     }
 
     @Test
-    public void groupWidgetItemsIntoTableWithoutReordering_maxSpanPxPerRow220_cellPadding0_shouldMaintainTheOrder() {
+    public void groupWithoutReordering_maxSpanPxPerRow220_cellPadding0() {
         List<WidgetItem> widgetItems =
                 List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4, mWidget2x2);
 
@@ -189,13 +225,19 @@
                 WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(widgetItems, mContext,
                         mTestDeviceProfile, 220, 0);
 
-        // Row 0: 4x4(230px)
-        // Row 1: 2x3(110px), 1x1(50px)
-        // Row 2: 2x4(110px), 2x2(110px)
-        assertThat(widgetItemInTable).hasSize(3);
+        // Without reordering, widgets are grouped only if the next one fits and uses same preview
+        // container:
+        // Row 0: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+        // Row 1: 2x3(in a 2x3 container - 110px)
+        // Row 2: 1x1(50px)
+        // Row 3: 2x4(in a 2x3 container - 110px)
+        // Row 4: 2x2(in a 2x2 container - 110px)
+        assertThat(widgetItemInTable).hasSize(5);
         assertThat(widgetItemInTable.get(0)).containsExactly(mWidget4x4);
-        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget1x1);
-        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x4, mWidget2x2);
+        assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3);
+        assertThat(widgetItemInTable.get(2)).containsExactly(mWidget1x1);
+        assertThat(widgetItemInTable.get(3)).containsExactly(mWidget2x4);
+        assertThat(widgetItemInTable.get(4)).containsExactly(mWidget2x2);
     }
 
     private void initDP() {
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 0e78565..245ec09 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -21,6 +21,7 @@
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.DEFAULT_POLL_INTERVAL;
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -55,9 +56,6 @@
 
     private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
     private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
-
-    private static final Pattern EVENT_ALT_ESC_DOWN = Pattern.compile(
-            "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
     private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
             "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
 
@@ -260,7 +258,7 @@
             int attempts = 0;
             final Rect margins = new Rect(
                     /* left= */ 0,
-                    getTopVisibleIconBounds(allAppsContainer).bottom,
+                    mHeight / 2,
                     /* right= */ 0,
                     /* bottom= */ getAppsListRecyclerBottomPadding());
 
@@ -362,6 +360,7 @@
 
     /**
      * Taps outside bottom sheet to dismiss it. Available on tablets only.
+     *
      * @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
      */
     public void dismissByTappingOutsideForTablet(boolean tapRight) {
@@ -375,7 +374,7 @@
                     ? mLauncher.waitForLauncherObject(FAST_SCROLLER_RES_ID) :
                     mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
 
-            mLauncher.touchOutsideContainer(container, tapRight, false);
+            touchOutside(tapRight, container);
             try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
                     "tapped outside AllApps bottom sheet")) {
                 verifyVisibleContainerOnDismiss();
@@ -383,10 +382,14 @@
         }
     }
 
+    protected void touchOutside(boolean tapRight, UiObject2 container) {
+        mLauncher.touchOutsideContainer(container, tapRight, false);
+    }
+
     /** Presses the meta keyboard shortcut to dismiss AllApps. */
     public void dismissByKeyboardShortcut() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+            pressMetaKey();
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                     "pressed meta key")) {
                 verifyVisibleContainerOnDismiss();
@@ -394,12 +397,18 @@
         }
     }
 
+    protected void pressMetaKey() {
+        mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+    }
+
     /** Presses the esc key to dismiss AllApps. */
     public void dismissByEscKey() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_DOWN);
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
-            mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE);
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE),
+                    NORMAL_STATE_ORDINAL,
+                    "pressing esc key");
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                     "pressed esc key")) {
                 verifyVisibleContainerOnDismiss();
@@ -407,10 +416,19 @@
         }
     }
 
+    /** Returns PrivateSpaceContainer if present in view. */
+    @NonNull
+    public PrivateSpaceContainer getPrivateSpaceUnlockedView() {
+        final UiObject2 allAppsContainer = verifyActiveContainer();
+        final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
+        return new PrivateSpaceContainer(mLauncher, appListRecycler);
+    }
+
     protected abstract void verifyVisibleContainerOnDismiss();
 
     /**
      * Return the QSB UI object on the AllApps screen.
+     *
      * @return the QSB UI object.
      */
     @NonNull
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 85098c8..7c6d684 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+
+import android.util.Log;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -36,9 +39,24 @@
         super(launcher, icon);
     }
 
+    /**
+     * Find an app icon with the given name.
+     *
+     * @param appName app icon to look for
+     */
+    static BySelector getAppIconSelector(String appName) {
+        // focusable=true to avoid matching folder labels
+        return By.clazz(TextView.class).text(makeMultilinePattern(appName)).focusable(true);
+    }
+
+    /**
+     * Find an app icon with the given name.
+     *
+     * @param appName  app icon to look for
+     * @param launcher (optional) - only match ui elements from Launcher's package
+     */
     static BySelector getAppIconSelector(String appName, LauncherInstrumentation launcher) {
-        return By.clazz(TextView.class).desc(makeMultilinePattern(appName))
-                .pkg(launcher.getLauncherPackageName());
+        return getAppIconSelector(appName).pkg(launcher.getLauncherPackageName());
     }
 
     static BySelector getMenuItemSelector(String text, LauncherInstrumentation launcher) {
@@ -80,6 +98,8 @@
 
     @Override
     protected void waitForLongPressConfirmation() {
+        Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                "AppIcon.waitForLongPressConfirmation, resName: popupContainer");
         mLauncher.waitForLauncherObject("popup_container");
     }
 
@@ -109,13 +129,16 @@
     }
 
     /**
-     * Create a regular expression pattern that matches strings starting with the app name, where
-     * spaces in the app name are replaced with zero or more occurrences of the "\s" character
-     * (which represents a whitespace character in regular expressions), followed by any characters
-     * after the app name.
+     * Create a regular expression pattern that matches strings containing all of the non-whitespace
+     * characters of the app name, with any amount of whitespace added between characters (e.g.
+     * newline for multiline app labels).
      */
     static Pattern makeMultilinePattern(String appName) {
-        return Pattern.compile(appName.replaceAll("\\s+", "\\\\s*") + ".*",
-                Pattern.DOTALL);
+        // Remove any existing whitespace.
+        appName = appName.replaceAll("\\s", "");
+        // Allow whitespace between characters, e.g. newline for 2 line app label.
+        StringBuilder regexBuldier = new StringBuilder("\\s*");
+        appName.chars().forEach(letter -> regexBuldier.append((char) letter).append("\\s*"));
+        return Pattern.compile(regexBuldier.toString());
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index 8713b68..988aa94 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -16,8 +16,7 @@
 
 package com.android.launcher3.tapl;
 
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
+import static com.android.launcher3.tapl.BaseOverview.TASK_RES_ID;
 import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
 
@@ -118,10 +117,10 @@
                         // non-tablet overview, snapshots can be on either side of the swiped
                         // task, but we still check that they become visible after swiping and
                         // pausing.
-                        mLauncher.waitForOverviewObject("snapshot");
+                        mLauncher.waitForOverviewObject(TASK_RES_ID);
                         if (mLauncher.isTablet()) {
                             List<UiObject2> tasks = mLauncher.getDevice().findObjects(
-                                    mLauncher.getOverviewObjectSelector("snapshot"));
+                                    mLauncher.getOverviewObjectSelector(TASK_RES_ID));
                             final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
                             mLauncher.assertTrue(
                                     "All tasks not to the left of the swiped task",
@@ -244,12 +243,11 @@
                     endY = startY;
                 }
 
-                mLauncher.executeAndWaitForEvent(
+                mLauncher.executeAndWaitForLauncherStop(
                         () -> mLauncher.linearGesture(
                                 startX, startY, endX, endY, 20, false,
                                 LauncherInstrumentation.GestureScope.EXPECT_PILFER),
-                        event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                        () -> "Quick switch gesture didn't change window state", "swiping");
+                        "swiping");
             } else {
                 // Double press the recents button.
                 UiObject2 recentsButton = mLauncher.waitForNavigationUiObject("recent_apps");
@@ -258,10 +256,8 @@
                         "clicking Recents button for the first time");
                 mLauncher.getOverview();
                 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, SQUARE_BUTTON_EVENT);
-                mLauncher.executeAndWaitForEvent(
+                mLauncher.executeAndWaitForLauncherStop(
                         () -> recentsButton.click(),
-                        event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                        () -> "Pressing recents button didn't change window state",
                         "clicking Recents button for the second time");
             }
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index b6b4a47..68829e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -16,9 +16,14 @@
 
 package com.android.launcher3.tapl;
 
+import static android.view.KeyEvent.KEYCODE_ESCAPE;
+
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
+import static com.android.launcher3.tapl.OverviewTask.TASK_START_EVENT;
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 
 import android.graphics.Rect;
+import android.view.KeyEvent;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -27,15 +32,26 @@
 import androidx.test.uiautomator.Direction;
 import androidx.test.uiautomator.UiObject2;
 
+import com.android.launcher3.testing.shared.TestProtocol;
+
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 /**
  * Common overview panel for both Launcher and fallback recents
  */
 public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
+    protected static final String TASK_RES_ID = "task";
+    private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
+    private static final Pattern EVENT_ENTER_DOWN = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ENTER");
+    private static final Pattern EVENT_ENTER_UP = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ENTER");
+
     private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
 
     BaseOverview(LauncherInstrumentation launcher) {
@@ -128,8 +144,19 @@
                 flingForwardImpl();
             }
 
-            mLauncher.clickLauncherObject(
-                    mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector));
+            final Runnable clickClearAll = () -> mLauncher.clickLauncherObject(
+                    mLauncher.waitForObjectInContainer(verifyActiveContainer(),
+                            clearAllSelector));
+            if (mLauncher.is3PLauncher()) {
+                mLauncher.executeAndWaitForLauncherStop(
+                        clickClearAll,
+                        "clicking 'Clear All'");
+            } else {
+                mLauncher.runToState(
+                        clickClearAll,
+                        NORMAL_STATE_ORDINAL,
+                        "clicking 'Clear All'");
+            }
 
             mLauncher.waitUntilLauncherObjectGone(clearAllSelector);
         }
@@ -150,9 +177,12 @@
 
             OverviewTask currentTask = flingToFirstTask();
 
-            mLauncher.touchOutsideContainer(currentTask.getUiObject(),
-                    /* tapRight= */ true,
-                    /* halfwayToEdge= */ false);
+            mLauncher.runToState(
+                    () -> mLauncher.touchOutsideContainer(currentTask.getUiObject(),
+                            /* tapRight= */ true,
+                            /* halfwayToEdge= */ false),
+                    NORMAL_STATE_ORDINAL,
+                    "touching outside of first task");
 
             return new Workspace(mLauncher);
         }
@@ -185,11 +215,15 @@
     public void touchTaskbarBottomCorner(boolean tapRight) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             Taskbar taskbar = new Taskbar(mLauncher);
-            taskbar.touchBottomCorner(tapRight);
             if (mLauncher.isTransientTaskbar()) {
+                mLauncher.runToState(
+                        () -> taskbar.touchBottomCorner(tapRight),
+                        NORMAL_STATE_ORDINAL,
+                        "touching taskbar");
                 // Tapping outside Transient Taskbar returns to Workspace, wait for that state.
                 new Workspace(mLauncher);
             } else {
+                taskbar.touchBottomCorner(tapRight);
                 // Should stay in Overview.
                 verifyActiveContainer();
                 verifyActionsViewVisibility();
@@ -245,10 +279,10 @@
 
         // The widest, and most top-right task should be the current task
         UiObject2 currentTask = Collections.max(taskViews,
-                Comparator.comparingInt((UiObject2 t) -> t.getParent().getVisibleBounds().width())
-                        .thenComparingInt((UiObject2 t) -> t.getParent().getVisibleCenter().x)
+                Comparator.comparingInt((UiObject2 t) -> t.getVisibleBounds().width())
+                        .thenComparingInt((UiObject2 t) -> t.getVisibleCenter().x)
                         .thenComparing(Comparator.comparing(
-                                (UiObject2 t) -> t.getParent().getVisibleCenter().y).reversed()));
+                                (UiObject2 t) -> t.getVisibleCenter().y).reversed()));
         return new OverviewTask(mLauncher, currentTask, this);
     }
 
@@ -293,10 +327,11 @@
                 "want to get overview tasks")) {
             verifyActiveContainer();
             return mLauncher.getDevice().findObjects(
-                    mLauncher.getOverviewObjectSelector("snapshot"));
+                    mLauncher.getOverviewObjectSelector(TASK_RES_ID));
         }
     }
 
+
     int getTaskCount() {
         return getTasks().size();
     }
@@ -363,8 +398,52 @@
         if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
             return false;
         }
-        // Overview actions aren't visible for split screen tasks.
-        return !task.isTaskSplit();
+        if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
+            // Overview actions aren't visible for split screen tasks, except for save app pair
+            // button on tablets.
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Presses the esc key to dismiss Overview.
+     */
+    public Workspace dismissByEscKey() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE),
+                    NORMAL_STATE_ORDINAL, "pressing esc key");
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                    "pressed esc key")) {
+                return mLauncher.getWorkspace();
+            }
+        }
+    }
+
+    /**
+     * Presses the enter key to launch the focused task
+     * <p>
+     * If no task is focused, this will fail.
+     */
+    public LaunchedAppState launchFocusedTaskByEnterKey(@NonNull String expectedPackageName) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ENTER_UP);
+            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
+
+            mLauncher.executeAndWaitForLauncherStop(
+                    () -> mLauncher.assertTrue(
+                            "Failed to press enter",
+                            mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_ENTER)),
+                    "pressing enter");
+            mLauncher.assertAppLaunched(expectedPackageName);
+
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                    "pressed enter")) {
+                return new LaunchedAppState(mLauncher);
+            }
+        }
     }
 
     private void verifyActionsViewVisibility() {
diff --git a/tests/tapl/com/android/launcher3/tapl/Folder.java b/tests/tapl/com/android/launcher3/tapl/Folder.java
index 1352cc0..b8adfe6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Folder.java
+++ b/tests/tapl/com/android/launcher3/tapl/Folder.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.tapl;
 
+import android.graphics.Rect;
+
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.UiObject2;
 
@@ -58,4 +60,7 @@
             return mLauncher.getWorkspace();
         }
     }
+    Rect getDropLocationBounds() {
+        return mLauncher.getVisibleBounds(mContainer);
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
index 0c453bd..080e52c 100644
--- a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
@@ -26,7 +26,7 @@
 /**
  * Folder Icon, an app folder in workspace.
  */
-public class FolderIcon implements FolderDragTarget {
+public class FolderIcon implements IconDragTarget {
 
     protected final UiObject2 mObject;
     protected final LauncherInstrumentation mLauncher;
@@ -60,7 +60,7 @@
 
     /** This method requires public access, however should not be called in tests. */
     @Override
-    public FolderIcon getTargetFolder(Rect bounds) {
+    public FolderIcon getTargetIcon(Rect bounds) {
         return this;
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 9ca2dc8..f8e1c10 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -30,8 +30,8 @@
 
     /**
      * Swipes up or down to dismiss to Workspace.
-     * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
      *
+     * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
      * @return the Workspace object.
      */
     @NonNull
@@ -131,4 +131,20 @@
             return new Workspace(mLauncher);
         }
     }
+
+    @Override
+    protected void touchOutside(boolean tapRight, UiObject2 container) {
+        mLauncher.runToState(
+                () -> super.touchOutside(tapRight, container),
+                NORMAL_STATE_ORDINAL,
+                "touching outside");
+    }
+
+    @Override
+    protected void pressMetaKey() {
+        mLauncher.runToState(
+                () -> super.pressMetaKey(),
+                NORMAL_STATE_ORDINAL,
+                "pressing meta key");
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
index 693baa0..ca85b29 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
@@ -27,7 +27,7 @@
 /**
  * App icon on the workspace or all apps.
  */
-public abstract class HomeAppIcon extends AppIcon implements FolderDragTarget, WorkspaceDragSource {
+public abstract class HomeAppIcon extends AppIcon implements IconDragTarget, WorkspaceDragSource {
 
     private final String mAppName;
 
@@ -42,7 +42,7 @@
      * @param target the destination icon.
      */
     @NonNull
-    public FolderIcon dragToIcon(FolderDragTarget target) {
+    public FolderIcon dragToIcon(IconDragTarget target) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
             final Rect dropBounds = target.getDropLocationBounds();
@@ -51,13 +51,33 @@
                     () -> {
                         final Rect bounds = target.getDropLocationBounds();
                         return new Point(bounds.centerX(), bounds.centerY());
-                    });
-            FolderIcon result = target.getTargetFolder(dropBounds);
+                    }, false);
+            FolderIcon result = target.getTargetIcon(dropBounds);
             mLauncher.assertTrue("Can't find the target folder.", result != null);
             return result;
         }
     }
 
+    /**
+     * Drag the AppIcon to the given position of a folder icon, and then inside that folder.
+     *
+     * @param target the destination folder.
+     */
+    @NonNull
+    public Folder dragToFolder(IconDragTarget target) {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
+            Workspace.dragIconToWorkspace(
+                    mLauncher, this,
+                    () -> {
+                        final Rect bounds = target.getDropLocationBounds();
+                        return new Point(bounds.centerX(), bounds.centerY());
+                    }, /* isDraggingToFolder */ true);
+        }
+        return new Folder(mLauncher);
+    }
+
+
     /** This method requires public access, however should not be called in tests. */
     @Override
     public Rect getDropLocationBounds() {
@@ -66,7 +86,7 @@
 
     /** This method requires public access, however should not be called in tests. */
     @Override
-    public FolderIcon getTargetFolder(Rect bounds) {
+    public FolderIcon getTargetIcon(Rect bounds) {
         for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
             final Rect folderIconBounds = folderIcon.getDropLocationBounds();
             if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
index 5385c65..c1fc45f 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeQsb.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
+
 import androidx.test.uiautomator.UiObject2;
 
 /**
@@ -25,4 +27,13 @@
     HomeQsb(LauncherInstrumentation launcher, UiObject2 hotseat) {
         super(launcher, hotseat, "search_container_hotseat");
     }
+
+    @Override
+    protected void clickQsb() {
+        // Clicking Qsb will switch to All Apps state.
+        mLauncher.runToState(
+                () -> super.clickQsb(),
+                ALL_APPS_STATE_ORDINAL,
+                "Clicking Qsb");
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java b/tests/tapl/com/android/launcher3/tapl/IconDragTarget.java
similarity index 91%
rename from tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
rename to tests/tapl/com/android/launcher3/tapl/IconDragTarget.java
index 2c60668..2f86703 100644
--- a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
+++ b/tests/tapl/com/android/launcher3/tapl/IconDragTarget.java
@@ -18,11 +18,11 @@
 
 import android.graphics.Rect;
 
-public interface FolderDragTarget {
+public interface IconDragTarget {
 
     /** This method requires public access, however should not be called in tests. */
     Rect getDropLocationBounds();
 
     /** This method requires public access, however should not be called in tests. */
-    FolderIcon getTargetFolder(Rect bounds);
+    FolderIcon getTargetIcon(Rect bounds);
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java b/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
index a1d8059..7ff55fe 100644
--- a/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
+++ b/tests/tapl/com/android/launcher3/tapl/KeyboardQuickSwitch.java
@@ -37,15 +37,9 @@
     private static final Pattern EVENT_ALT_TAB_UP = Pattern.compile(
             "KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_TAB"
                     + ".*?metaState=META_ALT_ON");
-    private static final Pattern EVENT_ALT_SHIFT_TAB_DOWN = Pattern.compile(
-            "KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_TAB"
-                    + ".*?metaState=META_ALT_ON|META_SHIFT_ON");
     private static final Pattern EVENT_ALT_SHIFT_TAB_UP = Pattern.compile(
             "KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_TAB"
                     + ".*?metaState=META_ALT_ON|META_SHIFT_ON");
-    private static final Pattern EVENT_ALT_ESC_DOWN = Pattern.compile(
-            "KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_DOWN"
-                    + ".*?keyCode=KEYCODE_ESCAPE.*?metaState=META_ALT_ON");
     private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
             "KeyboardQuickSwitchView key event: KeyEvent.*?action=ACTION_UP"
                     + ".*?keyCode=KEYCODE_ESCAPE.*?metaState=META_ALT_ON");
@@ -58,15 +52,15 @@
 
     private final LauncherInstrumentation mLauncher;
     private final LauncherInstrumentation.ContainerType mStartingContainerType;
-    private final boolean mExpectHomeKeyEventsOnDismiss;
+    private final boolean mIsHomeState;
 
     KeyboardQuickSwitch(
             LauncherInstrumentation launcher,
             LauncherInstrumentation.ContainerType startingContainerType,
-            boolean expectHomeKeyEventsOnDismiss) {
+            boolean isHomeState) {
         mLauncher = launcher;
         mStartingContainerType = startingContainerType;
-        mExpectHomeKeyEventsOnDismiss = expectHomeKeyEventsOnDismiss;
+        mIsHomeState = isHomeState;
     }
 
     /**
@@ -87,8 +81,6 @@
                 "want to move keyboard quick switch focus forward");
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
-
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_TAB_DOWN);
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_TAB_UP);
             mLauncher.assertTrue("Failed to press alt+tab",
                     mLauncher.getDevice().pressKeyCode(
@@ -122,7 +114,6 @@
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
 
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_SHIFT_TAB_DOWN);
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_SHIFT_TAB_UP);
             mLauncher.assertTrue("Failed to press alt+shift+tab",
                     mLauncher.getDevice().pressKeyCode(
@@ -150,7 +141,6 @@
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             mLauncher.waitForLauncherObject(KEYBOARD_QUICK_SWITCH_RES_ID);
 
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_DOWN);
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
             mLauncher.assertTrue("Failed to press alt+tab",
                     mLauncher.getDevice().pressKeyCode(
@@ -164,7 +154,7 @@
                 mLauncher.verifyContainerType(mStartingContainerType);
 
                 // Wait until the device has fully settled before unpressing the key code
-                if (mExpectHomeKeyEventsOnDismiss) {
+                if (mIsHomeState) {
                     mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_HOME_ALT_LEFT_UP);
                 }
                 mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
@@ -204,7 +194,14 @@
                 "want to launch focused task: "
                         + (expectedPackageName == null ? "Overview" : expectedPackageName))) {
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KQS_ALT_LEFT_UP);
-            mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
+
+            if (expectedPackageName == null || !mIsHomeState) {
+                mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0);
+            } else {
+                mLauncher.executeAndWaitForLauncherStop(
+                        () -> mLauncher.unpressKeyCode(KeyEvent.KEYCODE_ALT_LEFT, 0),
+                        "unpressing left alt");
+            }
 
             try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
                     "un-pressed left alt")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index fe927b3..9d3bc6e 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -16,11 +16,11 @@
 
 package com.android.launcher3.tapl;
 
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
 import static com.android.launcher3.testing.shared.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
 
 import android.graphics.Point;
+import android.util.Log;
 import android.view.MotionEvent;
 
 import androidx.test.uiautomator.UiObject2;
@@ -58,8 +58,8 @@
      */
     public LaunchedAppState launch(String expectedPackageName) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
-                    "want to launch an app from " + launchableType())) {
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(String.format(
+                    "want to launch an app (%s) from %s", expectedPackageName, launchableType()))) {
                 LauncherInstrumentation.log("Launchable.launch before click "
                         + mObject.getVisibleCenter() + " in "
                         + mLauncher.getVisibleBounds(mObject));
@@ -97,12 +97,10 @@
             LauncherInstrumentation.log("Launchable.launch before click "
                     + mObject.getVisibleCenter() + " in " + mLauncher.getVisibleBounds(
                     mObject));
-            mLauncher.executeAndWaitForLauncherEvent(
+
+            mLauncher.executeAndWaitForLauncherStop(
                     () -> mLauncher.clickLauncherObject(mObject),
-                    accessibilityEvent ->
-                            accessibilityEvent.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                    () -> "Unable to click object to launch split",
-                    "Click launcher object to launch split");
+                    "clicking the launchable");
 
             try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
                 mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, OverviewTask.SPLIT_START_EVENT);
@@ -117,11 +115,15 @@
                 iconCenter.y - getStartDragThreshold());
 
         if (runToSpringLoadedState) {
+            Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                    "Launchable.startDrag: actionName: long-pressing and triggering drag start"
+                            + " iconCenter: " + iconCenter + " dragStartCenter: "
+                            + dragStartCenter);
             mLauncher.runToState(() -> movePointerForStartDrag(
-                    downTime,
-                    iconCenter,
-                    dragStartCenter,
-                    expectLongClickEvents),
+                            downTime,
+                            iconCenter,
+                            dragStartCenter,
+                            expectLongClickEvents),
                     SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
         } else {
             movePointerForStartDrag(
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 184ece7..200f2ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -130,8 +130,11 @@
             int endX = startX;
             int endY = startY - taskbarFromNavThreshold;
 
-            mLauncher.linearGesture(startX, startY, endX, endY, 10, /* slowDown= */ true,
-                    LauncherInstrumentation.GestureScope.EXPECT_PILFER);
+            mLauncher.executeAndWaitForLauncherStop(
+                    () -> mLauncher.linearGesture(startX, startY, endX, endY, 10,
+                            /* slowDown= */ true,
+                            LauncherInstrumentation.GestureScope.EXPECT_PILFER),
+                    "swiping");
             LauncherInstrumentation.log("swipeUpToUnstashTaskbar: sent linear swipe up gesture");
 
             return new Taskbar(mLauncher);
@@ -346,10 +349,14 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "want to press back from launched app to workspace")) {
-            mLauncher.executeAndWaitForWallpaperAnimation(
-                    () -> mLauncher.pressBackImpl(),
-                    "pressing back"
-            );
+            if (mLauncher.isLauncher3()) {
+                mLauncher.pressBackImpl();
+            } else {
+                mLauncher.executeAndWaitForWallpaperAnimation(
+                        () -> mLauncher.pressBackImpl(),
+                        "pressing back"
+                );
+            }
             return new Workspace(mLauncher);
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 91ef472..ba8121f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -21,13 +21,18 @@
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
 import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_SCROLL;
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
+import static android.view.Surface.ROTATION_90;
 
 import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
 import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
 
 import android.app.ActivityManager;
 import android.app.Instrumentation;
@@ -91,7 +96,6 @@
 import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 import java.util.function.BooleanSupplier;
-import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.regex.Pattern;
@@ -109,9 +113,6 @@
 
     static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
     static final Pattern EVENT_START = Pattern.compile("start:");
-
-    private static final Pattern EVENT_KEY_BACK_DOWN =
-            getKeyEventPattern("ACTION_DOWN", "KEYCODE_BACK");
     private static final Pattern EVENT_KEY_BACK_UP =
             getKeyEventPattern("ACTION_UP", "KEYCODE_BACK");
     private static final Pattern EVENT_ON_BACK_INVOKED = Pattern.compile("onBackInvoked");
@@ -197,10 +198,11 @@
 
     private boolean mIgnoreTaskbarVisibility = false;
 
-    private Consumer<ContainerType> mOnSettledStateAction;
-
     private LogEventChecker mEventChecker;
 
+    // UI anomaly checker provided by the test.
+    private Runnable mTestAnomalyChecker;
+
     private boolean mCheckEventsForSuccessfulGestures = false;
     private Runnable mOnLauncherCrashed;
 
@@ -277,21 +279,35 @@
         assertNotNull("Cannot find content provider for " + testProviderAuthority, pi);
         ComponentName cn = new ComponentName(pi.packageName, pi.name);
 
+        final int iterations = isLauncherTest ? 300 : 100;
+
         if (pm.getComponentEnabledSetting(cn) != COMPONENT_ENABLED_STATE_ENABLED) {
             if (TestHelpers.isInLauncherProcess()) {
                 pm.setComponentEnabledSetting(cn, COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP);
             } else {
                 try {
                     final int userId = getContext().getUserId();
+                    final String launcherPidCommand = "pidof " + pi.packageName;
+                    final String initialPid = mDevice.executeShellCommand(launcherPidCommand);
+
                     mDevice.executeShellCommand(
                             "pm enable --user " + userId + " " + cn.flattenToString());
+
+                    // Wait for Launcher restart after enabling test provider.
+                    for (int i = 0; i < iterations; ++i) {
+                        final String currentPid = mDevice.executeShellCommand(launcherPidCommand)
+                                .replaceAll("\\s", "");
+                        if (!currentPid.isEmpty() && !currentPid.equals(initialPid)) break;
+                        if (i == iterations - 1) {
+                            fail("Launcher didn't restart after enabling test provider");
+                        }
+                        SystemClock.sleep(100);
+                    }
                 } catch (IOException e) {
                     fail(e.toString());
                 }
             }
 
-            final int iterations = isLauncherTest ? 300 : 100;
-
             // Wait for Launcher content provider to become enabled.
             for (int i = 0; i < iterations; ++i) {
                 final ContentProviderClient testProvider = getContext().getContentResolver()
@@ -370,8 +386,8 @@
                 .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
-    Insets getImeInsets() {
-        return getTestInfo(TestProtocol.REQUEST_IME_INSETS)
+    Insets getSystemGestureRegion() {
+        return getTestInfo(TestProtocol.REQUEST_SYSTEM_GESTURE_REGION)
                 .getParcelable(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
@@ -385,11 +401,26 @@
                 .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    private boolean isPredictiveBackSwipeEnabled() {
+        return getTestInfo(TestProtocol.REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED)
+                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
+    public boolean isTaskbarNavbarUnificationEnabled() {
+        return getTestInfo(TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION)
+                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     public boolean isTwoPanels() {
         return getTestInfo(TestProtocol.REQUEST_IS_TWO_PANELS)
                 .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    int getCellLayoutBoarderHeight() {
+        return getTestInfo(TestProtocol.REQUEST_CELL_LAYOUT_BOARDER_HEIGHT)
+                .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     int getFocusedTaskHeightForTablet() {
         return getTestInfo(TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET).getInt(
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -405,6 +436,11 @@
                 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    public int getOverviewCurrentPageIndex() {
+        return getTestInfo(TestProtocol.REQUEST_GET_OVERVIEW_CURRENT_PAGE_INDEX)
+                .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     float getExactScreenCenterX() {
         return getRealDisplaySize().x / 2f;
     }
@@ -437,12 +473,25 @@
         logShellCommand(cmd);
     }
 
+    /**
+     * Retrieves a resource value from context that defines if nav bar can change position or if it
+     * is fixed position regardless of device orientation.
+     */
+    private boolean getNavBarCanMove() {
+        final Context baseContext = mInstrumentation.getTargetContext();
+        try {
+            final Context ctx = getLauncherContext(baseContext);
+            return getNavBarCanMove(ctx);
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+        return false;
+    }
+
     public NavigationModel getNavigationModel() {
         final Context baseContext = mInstrumentation.getTargetContext();
         try {
-            // Workaround, use constructed context because both the instrumentation context and the
-            // app context are not constructed with resources that take overlays into account
-            final Context ctx = baseContext.createPackageContext(getLauncherPackageName(), 0);
+            final Context ctx = getLauncherContext(baseContext);
             for (int i = 0; i < 100; ++i) {
                 final int currentInteractionMode = getCurrentInteractionMode(ctx);
                 final NavigationModel model = getNavigationModel(currentInteractionMode);
@@ -546,8 +595,31 @@
         checkForAnomaly(false, false);
     }
 
+    /**
+     * Allows the test to provide a pluggable anomaly checker. It’s supposed to throw an exception
+     * if the check fails. The test may provide its own anomaly checker, for example, if it wants to
+     * check for an anomaly that’s recognized by the standard TAPL anomaly checker, but wants a
+     * custom error message, such as adding information whether the keyguard is seen for the first
+     * time during the shard execution.
+     */
+    public void setAnomalyChecker(Runnable anomalyChecker) {
+        mTestAnomalyChecker = anomalyChecker;
+    }
+
+    /**
+     * Verifies that there are no visible UI anomalies. An "anomaly" is a state of UI that should
+     * never happen during the text execution. Anomaly is something different from just “regular”
+     * unexpected state of the Launcher such as when we see Workspace after swiping up to All Apps.
+     * Workspace is a normal state. We can contrast this with an anomaly, when, for example, we see
+     * a lock screen. Launcher tests can never bring the lock screen, so the very presence of the
+     * lock screen is an indication that something went very wrong, and perhaps is caused by reasons
+     * outside of the Launcher and its tests, perhaps, by a crash in System UI. Diagnosing anomalies
+     * helps to understand faster whether the problem is in the Launcher or its tests, or outside.
+     */
     public void checkForAnomaly(
             boolean ignoreNavmodeChangeStates, boolean ignoreOnlySystemUiViews) {
+        if (mTestAnomalyChecker != null) mTestAnomalyChecker.run();
+
         final String systemAnomalyMessage =
                 getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
         if (systemAnomalyMessage != null) {
@@ -597,10 +669,6 @@
         this.mSystemHealthSupplier = supplier;
     }
 
-    public void setOnSettledStateAction(Consumer<ContainerType> onSettledStateAction) {
-        mOnSettledStateAction = onSettledStateAction;
-    }
-
     public void onTestStart() {
         mTestStartTime = System.currentTimeMillis();
     }
@@ -792,7 +860,8 @@
     }
 
     private String getNavigationButtonResPackage() {
-        return isTablet() ? getLauncherPackageName() : SYSTEMUI_PACKAGE;
+        return isTablet() || isTaskbarNavbarUnificationEnabled()
+                ? getLauncherPackageName() : SYSTEMUI_PACKAGE;
     }
 
     UiObject2 verifyContainerType(ContainerType containerType) {
@@ -810,8 +879,6 @@
 
         final UiObject2 container = verifyVisibleObjects(containerType);
 
-        if (mOnSettledStateAction != null) mOnSettledStateAction.accept(containerType);
-
         return container;
     }
 
@@ -853,7 +920,6 @@
                     waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
                     waitUntilLauncherObjectGone(WIDGETS_RES_ID);
                     waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
-                    waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
 
                     if (is3PLauncher() && isTablet() && !isTransientTaskbar()) {
@@ -862,6 +928,12 @@
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
                     }
 
+                    boolean splitSelectionActive = getTestInfo(REQUEST_GET_SPLIT_SELECTION_ACTIVE)
+                            .getBoolean(TEST_INFO_RESPONSE_FIELD);
+                    if (!splitSelectionActive) {
+                        waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
+                    } // do nothing, we expect that view
+
                     return waitForLauncherObject(APPS_RES_ID);
                 }
                 case OVERVIEW:
@@ -1007,11 +1079,11 @@
             return;
         }
 
-        linearGesture(
-                displaySize.x / 2, displaySize.y - 1,
-                displaySize.x / 2, 0,
-                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                false, GestureScope.EXPECT_PILFER);
+        if (isLauncher3()) {
+            gestureToDismissPopup(displaySize);
+        } else {
+            runToState(() -> gestureToDismissPopup(displaySize), NORMAL_STATE_ORDINAL, "swiping");
+        }
 
         try (LauncherInstrumentation.Closable c1 = addContextLayer(
                 String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
@@ -1020,6 +1092,14 @@
         }
     }
 
+    private void gestureToDismissPopup(Point displaySize) {
+        linearGesture(
+                displaySize.x / 2, displaySize.y - 1,
+                displaySize.x / 2, 0,
+                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                false, GestureScope.EXPECT_PILFER);
+    }
+
     /**
      * @return the Workspace object.
      * @deprecated use goHome().
@@ -1033,19 +1113,31 @@
     /**
      * Goes to home from immersive fullscreen app by first swiping up to bring navbar, and then
      * performing {@code goHome()} action.
-     * Currently only supports gesture navigation mode.
      *
      * @return the Workspace object.
      */
     public Workspace goHomeFromImmersiveFullscreenApp() {
-        assertTrue("expected gesture navigation mode",
-                getNavigationModel() == NavigationModel.ZERO_BUTTON);
-        final Point displaySize = getRealDisplaySize();
-        linearGesture(
-                displaySize.x / 2, displaySize.y - 1,
-                displaySize.x / 2, 0,
-                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                false, GestureScope.EXPECT_PILFER);
+        final boolean navBarCanMove = getNavBarCanMove();
+        if (getNavigationModel() == NavigationModel.ZERO_BUTTON || !navBarCanMove) {
+            // in gesture nav we can swipe up at the bottom to bring the navbar handle
+            final Point displaySize = getRealDisplaySize();
+            linearGesture(
+                    displaySize.x / 2, displaySize.y - 1,
+                    displaySize.x / 2, 0,
+                    ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                    false, GestureScope.EXPECT_PILFER);
+        } else {
+            // in 3 button nav we swipe up on the side edge of the screen to bring the navbar
+            final boolean rotated90degrees = mDevice.getDisplayRotation() == ROTATION_90;
+            final Point displaySize = getRealDisplaySize();
+            final int startX = rotated90degrees ? displaySize.x : 0;
+            final int endX = rotated90degrees ? 0 : displaySize.x;
+            linearGesture(
+                    startX, displaySize.y / 2,
+                    endX, displaySize.y / 2,
+                    ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                    false, GestureScope.EXPECT_PILFER);
+        }
         return goHome();
     }
 
@@ -1100,7 +1192,11 @@
                 log("Hierarchy before clicking home:");
                 dumpViewHierarchy();
                 action = "clicking home button";
-
+                Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                        "LauncherInstrumentation.goHome: isThreeFingerTrackpadGesture: "
+                                + isThreeFingerTrackpadGesture
+                                + "getNavigationModel() == NavigationModel.ZERO_BUTTON: " + (
+                                getNavigationModel() == NavigationModel.ZERO_BUTTON));
                 runToState(
                         getHomeButton()::click,
                         NORMAL_STATE_ORDINAL,
@@ -1144,10 +1240,9 @@
             waitForNavigationUiObject("back").click();
         }
         if (launcherVisible) {
-            if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
+            if (isPredictiveBackSwipeEnabled()) {
                 expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
             } else {
-                expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
                 expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
             }
         }
@@ -1446,6 +1541,8 @@
 
     @NonNull
     UiObject2 waitForLauncherObject(String resName) {
+        Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                "LauncherInstrumentation.waitForLauncherObject");
         return waitForObjectBySelector(getLauncherObjectSelector(resName));
     }
 
@@ -1475,12 +1572,16 @@
 
     @NonNull
     List<UiObject2> waitForObjectsBySelector(BySelector selector) {
+        Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                "LauncherInstrumentation.waitForObjectsBySelector");
         final List<UiObject2> objects = mDevice.wait(Until.findObjects(selector), WAIT_TIME_MS);
         assertNotNull("Can't find any view in Launcher, selector: " + selector, objects);
         return objects;
     }
 
     private UiObject2 waitForObjectBySelector(BySelector selector) {
+        Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                "LauncherInstrumentation.waitForObjectBySelector");
         final UiObject2 object = mDevice.wait(Until.findObject(selector), WAIT_TIME_MS);
         assertNotNull("Can't find a view in Launcher, selector: " + selector, object);
         return object;
@@ -1523,13 +1624,17 @@
 
     void runToState(Runnable command, int expectedState, boolean requireEvent, String actionName) {
         if (requireEvent) {
+            Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                    "LauncherInstrumentation.runToState: command: " + command + " expectedState: "
+                            + expectedState + " actionName: " + actionName + "requireEvent: true");
             runToState(command, expectedState, actionName);
         } else {
             command.run();
         }
     }
 
-    void runToState(Runnable command, int expectedState, String actionName) {
+    /** Run an action and wait for the specified Launcher state. */
+    public void runToState(Runnable command, int expectedState, String actionName) {
         final List<Integer> actualEvents = new ArrayList<>();
         executeAndWaitForLauncherEvent(
                 command,
@@ -1702,6 +1807,16 @@
                 "scrolling");
     }
 
+    void pointerScroll(float pointerX, float pointerY, Direction direction) {
+        executeAndWaitForLauncherEvent(
+                () -> injectEvent(getPointerMotionEvent(
+                        ACTION_SCROLL, pointerX, pointerY, direction)),
+                event -> TestProtocol.SCROLL_FINISHED_MESSAGE.equals(event.getClassName()),
+                () -> "Didn't receive a scroll end message: " + direction + " scroll from ("
+                        + pointerX + ", " + pointerY + ")",
+                "scrolling");
+    }
+
     // Inject a swipe gesture. Inject exactly 'steps' motion points, incrementing event time by a
     // fixed interval each time.
     public void linearGesture(int startX, int startY, int endX, int endY, int steps,
@@ -1710,32 +1825,38 @@
         final long downTime = SystemClock.uptimeMillis();
         final Point start = new Point(startX, startY);
         final Point end = new Point(endX, endY);
+        long endTime = downTime;
         sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
-        if (mTrackpadGestureType != TrackpadGestureType.NONE) {
-            sendPointer(downTime, downTime, getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
-                    start, gestureScope);
-            if (mTrackpadGestureType == TrackpadGestureType.THREE_FINGER
-                    || mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+        try {
+
+            if (mTrackpadGestureType != TrackpadGestureType.NONE) {
                 sendPointer(downTime, downTime,
-                        getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+                        getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 1),
                         start, gestureScope);
-                if (mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+                if (mTrackpadGestureType == TrackpadGestureType.THREE_FINGER
+                        || mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
                     sendPointer(downTime, downTime,
-                            getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 3),
+                            getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 2),
+                            start, gestureScope);
+                    if (mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER) {
+                        sendPointer(downTime, downTime,
+                                getPointerAction(MotionEvent.ACTION_POINTER_DOWN, 3),
+                                start, gestureScope);
+                    }
+                }
+            }
+            endTime = movePointer(
+                    start, end, steps, false, downTime, downTime, slowDown, gestureScope);
+        } finally {
+            if (mTrackpadGestureType != TrackpadGestureType.NONE) {
+                for (int i = mPointerCount; i >= 2; i--) {
+                    sendPointer(downTime, downTime,
+                            getPointerAction(MotionEvent.ACTION_POINTER_UP, i - 1),
                             start, gestureScope);
                 }
             }
+            sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
         }
-        final long endTime = movePointer(
-                start, end, steps, false, downTime, downTime, slowDown, gestureScope);
-        if (mTrackpadGestureType != TrackpadGestureType.NONE) {
-            for (int i = mPointerCount; i >= 2; i--) {
-                sendPointer(downTime, downTime,
-                        getPointerAction(MotionEvent.ACTION_POINTER_UP, i - 1),
-                        start, gestureScope);
-            }
-        }
-        sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
     }
 
     private static int getPointerAction(int action, int index) {
@@ -1765,6 +1886,41 @@
         return getContext().getResources();
     }
 
+    private static MotionEvent getPointerMotionEvent(
+            int action, float x, float y, Direction direction) {
+        MotionEvent.PointerCoords[] coordinates = new MotionEvent.PointerCoords[1];
+        coordinates[0] = new MotionEvent.PointerCoords();
+        coordinates[0].x = x;
+        coordinates[0].y = y;
+        boolean isVertical = direction == Direction.UP || direction == Direction.DOWN;
+        boolean isForward = direction == Direction.RIGHT || direction == Direction.DOWN;
+        coordinates[0].setAxisValue(
+                isVertical ? MotionEvent.AXIS_VSCROLL : MotionEvent.AXIS_HSCROLL,
+                isForward ? 1f : -1f);
+
+        MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1];
+        properties[0] = new MotionEvent.PointerProperties();
+        properties[0].id = 0;
+        properties[0].toolType = MotionEvent.TOOL_TYPE_MOUSE;
+
+        final long downTime = SystemClock.uptimeMillis();
+        return MotionEvent.obtain(
+                downTime,
+                downTime,
+                action,
+                /* pointerCount= */ 1,
+                properties,
+                coordinates,
+                /* metaState= */ 0,
+                /* buttonState= */ 0,
+                /* xPrecision= */ 1f,
+                /* yPrecision= */ 1f,
+                /* deviceId= */ 0,
+                /* edgeFlags= */ 0,
+                InputDevice.SOURCE_CLASS_POINTER,
+                /* flags= */ 0);
+    }
+
     private static MotionEvent getTrackpadMotionEvent(long downTime, long eventTime,
             int action, float x, float y, int pointerCount, TrackpadGestureType gestureType) {
         MotionEvent.PointerProperties[] pointerProperties =
@@ -1787,17 +1943,21 @@
     }
 
     private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
-            float x, float y, int source) {
+            float x, float y, int source, int toolType) {
         return MotionEvent.obtain(downTime, eventTime, action, 1,
-                new MotionEvent.PointerProperties[]{getPointerProperties(0)},
+                new MotionEvent.PointerProperties[]{getPointerProperties(0, toolType)},
                 new MotionEvent.PointerCoords[]{getPointerCoords(x, y)},
                 0, 0, 1.0f, 1.0f, 0, 0, source, 0);
     }
 
     private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
+        return getPointerProperties(pointerId, Configurator.getInstance().getToolType());
+    }
+
+    private static MotionEvent.PointerProperties getPointerProperties(int pointerId, int toolType) {
         MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
         properties.id = pointerId;
-        properties.toolType = Configurator.getInstance().getToolType();
+        properties.toolType = toolType;
         return properties;
     }
 
@@ -1820,6 +1980,11 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    boolean isAppPairsEnabled() {
+        return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_APP_PAIRS).getBoolean(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope) {
         sendPointer(downTime, currentTime, action, point, gestureScope,
@@ -1838,6 +2003,19 @@
 
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope, int source, boolean isRightClick) {
+        sendPointer(
+                downTime,
+                currentTime,
+                action,
+                point,
+                gestureScope,
+                source,
+                isRightClick,
+                Configurator.getInstance().getToolType());
+    }
+
+    public void sendPointer(long downTime, long currentTime, int action, Point point,
+            GestureScope gestureScope, int source, boolean isRightClick, int toolType) {
         final boolean hasTIS = hasTIS();
         int pointerCount = mPointerCount;
 
@@ -1848,11 +2026,15 @@
                     mPointerCount = 1;
                     pointerCount = mPointerCount;
                 }
+                Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                        "LauncherInstrumentation.sendPointer: ACTION_DOWN");
                 break;
             case MotionEvent.ACTION_UP:
                 if (hasTIS && gestureScope == GestureScope.EXPECT_PILFER) {
                     expectEvent(TestProtocol.SEQUENCE_PILFER, EVENT_PILFER_POINTERS);
                 }
+                Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                        "LauncherInstrumentation.sendPointer: ACTION_UP");
                 break;
             case MotionEvent.ACTION_POINTER_DOWN:
                 mPointerCount++;
@@ -1868,13 +2050,13 @@
                 ? getTrackpadMotionEvent(
                 downTime, currentTime, action, point.x, point.y, pointerCount,
                 mTrackpadGestureType)
-                : getMotionEvent(downTime, currentTime, action, point.x, point.y, source);
+                : getMotionEvent(downTime, currentTime, action, point.x, point.y, source, toolType);
         if (action == MotionEvent.ACTION_BUTTON_PRESS
                 || action == MotionEvent.ACTION_BUTTON_RELEASE) {
             event.setActionButton(MotionEvent.BUTTON_PRIMARY);
         }
         if (isRightClick) {
-            event.setButtonState(event.getButtonState() & MotionEvent.BUTTON_SECONDARY);
+            event.setButtonState(event.getButtonState() | MotionEvent.BUTTON_SECONDARY);
         }
         injectEvent(event);
     }
@@ -1968,18 +2150,32 @@
         return getSystemIntegerRes(context, "config_navBarInteractionMode");
     }
 
+    /**
+     * Retrieve the resource value that defines if nav bar can moved or if it is fixed position.
+     */
+    private static boolean getNavBarCanMove(Context context) {
+        return getSystemBooleanRes(context, "config_navBarCanMove");
+    }
+
     @NonNull
     UiObject2 clickAndGet(
             @NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
         final Point targetCenter = target.getVisibleCenter();
         final long downTime = SystemClock.uptimeMillis();
+        // Use stylus secondary button press to prevent using the exteded long press timeout rule
+        // unnecessarily
         sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
-                GestureScope.DONT_EXPECT_PILFER);
-        expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
-        final UiObject2 result = waitForLauncherObject(resName);
-        sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
-                GestureScope.DONT_EXPECT_PILFER);
-        return result;
+                GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_TOUCHSCREEN,
+                /* isRightClick= */ true, MotionEvent.TOOL_TYPE_STYLUS);
+        try {
+            expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
+            final UiObject2 result = waitForLauncherObject(resName);
+            return result;
+        } finally {
+            sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
+                    GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_TOUCHSCREEN,
+                    /* isRightClick= */ true, MotionEvent.TOOL_TYPE_STYLUS);
+        }
     }
 
     @NonNull
@@ -1990,12 +2186,27 @@
         sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
                 GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
                 /* isRightClick= */ true);
-        expectEvent(TestProtocol.SEQUENCE_MAIN, rightClickEvent);
-        final UiObject2 result = waitForLauncherObject(resName);
-        sendPointer(downTime, SystemClock.uptimeMillis(), ACTION_UP, targetCenter,
-                GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
-                /* isRightClick= */ true);
-        return result;
+        try {
+            expectEvent(TestProtocol.SEQUENCE_MAIN, rightClickEvent);
+            final UiObject2 result = waitForLauncherObject(resName);
+            return result;
+        } finally {
+            sendPointer(downTime, SystemClock.uptimeMillis(), ACTION_UP, targetCenter,
+                    GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_MOUSE,
+                    /* isRightClick= */ true);
+        }
+    }
+
+    private static boolean getSystemBooleanRes(Context context, String resName) {
+        Resources res = context.getResources();
+        int resId = res.getIdentifier(resName, "bool", "android");
+
+        if (resId != 0) {
+            return res.getBoolean(resId);
+        } else {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+            return false;
+        }
     }
 
     private static int getSystemIntegerRes(Context context, String resName) {
@@ -2094,6 +2305,11 @@
         getTestInfo(TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED);
     }
 
+    /** Shows the bubble bar if it is stashed, otherwise this does nothing. */
+    public void showBubbleBarIfHidden() {
+        getTestInfo(TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED);
+    }
+
     /** Blocks the taskbar from automatically stashing based on time. */
     public void enableBlockTimeout(boolean enable) {
         getTestInfo(enable
@@ -2106,6 +2322,11 @@
                 .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    public boolean isImeDocked() {
+        return getTestInfo(TestProtocol.REQUEST_TASKBAR_IME_DOCKED).getBoolean(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     /** Enables transient taskbar for testing purposes only. */
     public void enableTransientTaskbar(boolean enable) {
         getTestInfo(enable
@@ -2249,6 +2470,13 @@
         return Math.max(topRadius, bottomRadius) + tmpBuffer;
     }
 
+    private Context getLauncherContext(Context baseContext)
+            throws PackageManager.NameNotFoundException {
+        // Workaround, use constructed context because both the instrumentation context and the
+        // app context are not constructed with resources that take overlays into account
+        return baseContext.createPackageContext(getLauncherPackageName(), 0);
+    }
+
     private static boolean supportsRoundedCornersOnWindows(Resources resources) {
         return ResourceUtils.getBoolByName(
                 "config_supportsRoundedCornersOnWindows", resources, false);
@@ -2287,12 +2515,13 @@
                         : containerBounds.left - 1;
             }
             // If IME is visible and overlaps the container bounds, touch above it.
+            final Insets systemGestureRegion = getSystemGestureRegion();
             int bottomBound = Math.min(
                     containerBounds.bottom,
-                    getRealDisplaySize().y - getImeInsets().bottom);
+                    getRealDisplaySize().y - systemGestureRegion.bottom);
             int y = (bottomBound + containerBounds.top) / 2;
             // Do not tap in the status bar.
-            y = Math.max(y, getWindowInsets().top);
+            y = Math.max(y, systemGestureRegion.top);
 
             final long downTime = SystemClock.uptimeMillis();
             final Point tapTarget = new Point(x, y);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index bd2c9c1..486a63b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.tapl;
 
 import androidx.annotation.NonNull;
+import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiObject2;
 
 /**
@@ -89,8 +90,7 @@
     private SelectModeButtons getSelectModeButtons() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get select mode buttons")) {
-            UiObject2 selectModeButtons = mLauncher.waitForLauncherObject("select_mode_buttons");
-            return new SelectModeButtons(selectModeButtons, mLauncher);
+            return new SelectModeButtons(mLauncher);
         }
     }
 
@@ -111,4 +111,12 @@
             }
         }
     }
+
+    /** Asserts that an item matching the given string is present in the overview actions. */
+    public void assertHasAction(String text) {
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "want to check if the action [" + text + "] is present")) {
+            mLauncher.waitForObjectInContainer(mOverviewActions, By.text(text));
+        }
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index f383e99..6f420af 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,9 +16,14 @@
 
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
+import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
+
 import android.graphics.Rect;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiObject2;
@@ -34,9 +39,6 @@
  */
 public final class OverviewTask {
     private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
-    private static final String TASK_SNAPSHOT_1 = "snapshot";
-    private static final String TASK_SNAPSHOT_2 = "bottomright_snapshot";
-
     static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync");
     static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect");
     static final Pattern SPLIT_START_EVENT = Pattern.compile("launchSplitTasks");
@@ -64,15 +66,16 @@
             return getCombinedSplitTaskHeight();
         }
 
-        return mTask.getVisibleBounds().height();
+        UiObject2 taskSnapshot1 = findObjectInTask(DEFAULT.snapshotRes);
+        return taskSnapshot1.getVisibleBounds().height();
     }
 
     /**
      * Calculates the visible height for split tasks, containing 2 snapshot tiles and a divider.
      */
     private int getCombinedSplitTaskHeight() {
-        UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
-        UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
+        UiObject2 taskSnapshot1 = findObjectInTask(SPLIT_TOP_OR_LEFT.snapshotRes);
+        UiObject2 taskSnapshot2 = findObjectInTask(SPLIT_BOTTOM_OR_RIGHT.snapshotRes);
 
         // If the split task is partly off screen, taskSnapshot1 can be invisible.
         if (taskSnapshot1 == null) {
@@ -96,15 +99,16 @@
             return getCombinedSplitTaskWidth();
         }
 
-        return mTask.getVisibleBounds().width();
+        UiObject2 taskSnapshot1 = findObjectInTask(DEFAULT.snapshotRes);
+        return taskSnapshot1.getVisibleBounds().width();
     }
 
     /**
      * Calculates the visible width for split tasks, containing 2 snapshot tiles and a divider.
      */
     private int getCombinedSplitTaskWidth() {
-        UiObject2 taskSnapshot1 = findObjectInTask(TASK_SNAPSHOT_1);
-        UiObject2 taskSnapshot2 = findObjectInTask(TASK_SNAPSHOT_2);
+        UiObject2 taskSnapshot1 = findObjectInTask(SPLIT_TOP_OR_LEFT.snapshotRes);
+        UiObject2 taskSnapshot2 = findObjectInTask(SPLIT_BOTTOM_OR_RIGHT.snapshotRes);
 
         int left = Math.min(
                 taskSnapshot1.getVisibleBounds().left, taskSnapshot2.getVisibleBounds().left);
@@ -115,15 +119,15 @@
     }
 
     int getTaskCenterX() {
-        return mTask.getParent().getVisibleCenter().x;
+        return mTask.getVisibleCenter().x;
     }
 
     int getTaskCenterY() {
-        return mTask.getParent().getVisibleCenter().y;
+        return mTask.getVisibleCenter().y;
     }
 
     float getExactCenterX() {
-        return mTask.getParent().getVisibleBounds().exactCenterX();
+        return mTask.getVisibleBounds().exactCenterX();
     }
 
     UiObject2 getUiObject() {
@@ -225,11 +229,17 @@
     /** Taps the task menu. Returns the task menu object. */
     @NonNull
     public OverviewTaskMenu tapMenu() {
+        return tapMenu(DEFAULT);
+    }
+
+    /** Taps the task menu of the split task. Returns the split task's menu object. */
+    @NonNull
+    public OverviewTaskMenu tapMenu(OverviewSplitTask task) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "want to tap the task menu")) {
             mLauncher.clickLauncherObject(
-                    mLauncher.waitForObjectInContainer(mTask.getParent(), "icon"));
+                    mLauncher.waitForObjectInContainer(mTask, task.iconAppRes));
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped the task menu")) {
@@ -238,27 +248,48 @@
         }
     }
 
-    /** Taps the task menu of the split task. Returns the split task's menu object. */
-    @NonNull
-    public OverviewTaskMenu tapSplitTaskMenu() {
-        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
-             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                     "want to tap the split task's menu")) {
-            mLauncher.clickLauncherObject(
-                    mLauncher.waitForObjectInContainer(mTask.getParent(), "bottomRight_icon"));
-
-            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
-                    "tapped the split task's menu")) {
-                return new OverviewTaskMenu(mLauncher);
-            }
-        }
-    }
-
     boolean isTaskSplit() {
-        return findObjectInTask(TASK_SNAPSHOT_2) != null;
+        return findObjectInTask(SPLIT_BOTTOM_OR_RIGHT.snapshotRes) != null;
     }
 
     private UiObject2 findObjectInTask(String resName) {
-        return mTask.getParent().findObject(mLauncher.getOverviewObjectSelector(resName));
+        return mTask.findObject(mLauncher.getOverviewObjectSelector(resName));
+    }
+
+    /**
+     * Returns whether the given String is contained in this Task's contentDescription. Also returns
+     * true if both Strings are null.
+     *
+     * TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed.
+     */
+    public boolean containsContentDescription(@Nullable String expected) {
+        String actual = mTask.getContentDescription();
+        if (actual == null && expected == null) {
+            return true;
+        }
+        if (actual == null || expected == null) {
+            return false;
+        }
+        return actual.contains(expected);
+    }
+
+    /**
+     * Enum used to specify  which task is retrieved when it is a split task.
+     */
+    public enum OverviewSplitTask {
+        // The main task when the task is not split.
+        DEFAULT("snapshot", "icon"),
+        // The first task in split task.
+        SPLIT_TOP_OR_LEFT("snapshot", "icon"),
+        // The second task in split task.
+        SPLIT_BOTTOM_OR_RIGHT("bottomright_snapshot", "bottomRight_icon");
+
+        public final String snapshotRes;
+        public final String iconAppRes;
+
+        OverviewSplitTask(String snapshotRes, String iconAppRes) {
+            this.snapshotRes = snapshotRes;
+            this.iconAppRes = iconAppRes;
+        }
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 3d2914d..902ad5b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -16,6 +16,9 @@
 
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_MODAL_TASK_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_SPLIT_SELECT_ORDINAL;
+
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiObject2;
@@ -40,8 +43,11 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "tap split menu item")) {
-            mLauncher.clickLauncherObject(
-                    mLauncher.findObjectInContainer(mMenu, By.textStartsWith("Split")));
+            mLauncher.runToState(() -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.textStartsWith("Split"))),
+                    OVERVIEW_SPLIT_SELECT_ORDINAL,
+                    "tapping split menu item"
+            );
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped split menu item")) {
@@ -72,6 +78,25 @@
         }
     }
 
+    /** Taps the select menu item from the overview task menu. */
+    @NonNull
+    public SelectModeButtons tapSelectMenuItem() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "before tapping the select menu item")) {
+
+            mLauncher.runToState(
+                    () -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.text("Select"))),
+                    OVERVIEW_MODAL_TASK_STATE_ORDINAL, "tapping select menu item");
+
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "select menu item opened")) {
+                return new SelectModeButtons(mLauncher);
+            }
+        }
+    }
+
     /** Returns true if an item matching the given string is present in the menu. */
     public boolean hasMenuItem(String expectedMenuItemText) {
         UiObject2 menuItem = mLauncher.findObjectInContainer(mMenu, By.text(expectedMenuItemText));
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
new file mode 100644
index 0000000..2c16e01
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceContainer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * View containing Private Space elements.
+ */
+public class PrivateSpaceContainer {
+    private static final String PS_HEADER_RES_ID = "ps_header_layout";
+    private static final String INSTALL_APP_TITLE = "Install apps";
+    private static final String DIVIDER_RES_ID = "private_space_divider";
+
+    private final LauncherInstrumentation mLauncher;
+    private final UiObject2 mAppListRecycler;
+
+    PrivateSpaceContainer(LauncherInstrumentation launcherInstrumentation,
+            UiObject2 appListRecycler) {
+        mLauncher = launcherInstrumentation;
+        mAppListRecycler = appListRecycler;
+
+        verifyHeaderIsPresent();
+        verifyInstallAppButtonIsPresent();
+        verifyDividerIsPresent();
+    }
+
+    // Assert PS Header is in view.
+    // Assert PS header has the correct elements.
+    private void verifyHeaderIsPresent() {
+        final UiObject2 psHeader = mLauncher.waitForObjectInContainer(mAppListRecycler,
+                PS_HEADER_RES_ID);
+        new PrivateSpaceHeader(mLauncher, psHeader, true);
+    }
+
+
+    // Assert Install App Item is present in view.
+    private void verifyInstallAppButtonIsPresent() {
+        mLauncher.getAllApps().getAppIcon(INSTALL_APP_TITLE);
+    }
+
+    // Assert Sys App Divider is present in view.
+    private void verifyDividerIsPresent() {
+        mLauncher.waitForObjectInContainer(mAppListRecycler, DIVIDER_RES_ID);
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
new file mode 100644
index 0000000..3a7f038
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/PrivateSpaceHeader.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import androidx.test.uiautomator.UiObject2;
+
+/**
+ * View containing Private Space Header.
+ */
+public class PrivateSpaceHeader {
+    private static final String PS_HEADER_TEXT_RES_ID = "ps_container_header";
+    private static final String SETTINGS_BUTTON_RES_ID = "ps_settings_button";
+    private static final String UNLOCK_BUTTON_VIEW_RES_ID = "ps_lock_unlock_button";
+    private static final String LOCK_ICON_RES_ID = "lock_icon";
+    private static final String LOCK_TEXT_RES_ID = "lock_text";
+
+    private final UiObject2 mPrivateSpaceHeader;
+    private final boolean mPrivateSpaceEnabled;
+    private final LauncherInstrumentation mLauncher;
+
+    PrivateSpaceHeader(LauncherInstrumentation launcherInstrumentation,
+            UiObject2 privateSpaceHeader, boolean privateSpaceEnabled) {
+        mLauncher = launcherInstrumentation;
+        mPrivateSpaceHeader = privateSpaceHeader;
+        mPrivateSpaceEnabled =  privateSpaceEnabled;
+        verifyPrivateSpaceHeaderState();
+    }
+
+    /** Verify elements in Private Space Header as per state */
+    private void verifyPrivateSpaceHeaderState() {
+        if (mPrivateSpaceEnabled) {
+            verifyUnlockedState();
+        } else {
+            mLauncher.fail("Private Space found in non enabled state");
+        }
+    }
+
+    /** Verify Unlocked State elements in Private Space Header */
+    private void verifyUnlockedState() {
+        UiObject2 headerText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                PS_HEADER_TEXT_RES_ID);
+        mLauncher.assertEquals("PS Header Text is incorrect ",
+                "Private", headerText.getText());
+
+        UiObject2 settingsButton = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                SETTINGS_BUTTON_RES_ID);
+        mLauncher.waitForObjectEnabled(settingsButton, "Private Space Settings Button");
+        mLauncher.assertTrue("PS Settings button is non-clickable", settingsButton.isClickable());
+
+        UiObject2 unLockButtonView = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                UNLOCK_BUTTON_VIEW_RES_ID);
+        mLauncher.waitForObjectEnabled(unLockButtonView, "Private Space Unlock Button");
+        mLauncher.assertTrue("PS Unlock Button is non-clickable", unLockButtonView.isClickable());
+
+        mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                LOCK_ICON_RES_ID);
+
+        UiObject2 lockText = mLauncher.waitForObjectInContainer(mPrivateSpaceHeader,
+                LOCK_TEXT_RES_ID);
+        mLauncher.assertEquals("PS lock text is incorrect", "Lock", lockText.getText());
+
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
index fe2a63d..d67b8a3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Qsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -118,9 +118,7 @@
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to open search result page");
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            mLauncher.clickLauncherObject(waitForQsbObject());
-            // wait for the result rendering to complete
-            mLauncher.waitForIdle();
+            clickQsb();
             try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
                     "clicked qsb to open search result page")) {
                 return createSearchResult();
@@ -128,6 +126,10 @@
         }
     }
 
+    protected void clickQsb() {
+        mLauncher.clickLauncherObject(waitForQsbObject());
+    }
+
     @Override
     public LauncherInstrumentation getLauncher() {
         return mLauncher;
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index f0a8aa2..8d3a631 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+
 import android.widget.TextView;
 
 import androidx.test.uiautomator.By;
@@ -39,7 +41,7 @@
 
     /** Find the app from search results with app name. */
     public AppIcon findAppIcon(String appName) {
-        UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
+        UiObject2 icon = mLauncher.waitForLauncherObject(AppIcon.getAppIconSelector(appName));
         return createAppIcon(icon);
     }
 
@@ -87,7 +89,7 @@
                              + (tapRight ? "right" : "left"))) {
             final UiObject2 allAppsBottomSheet =
                     mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
-            mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+            tapOutside(tapRight, allAppsBottomSheet);
             try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
                     "tapped outside AllApps bottom sheet")) {
                 verifyVisibleContainerOnDismiss();
@@ -95,6 +97,13 @@
         }
     }
 
+    protected void tapOutside(boolean tapRight, UiObject2 allAppsBottomSheet) {
+        mLauncher.runToState(
+                () -> mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight),
+                NORMAL_STATE_ORDINAL,
+                "tappig outside");
+    }
+
     protected void verifyVisibleContainerOnDismiss() {
         mLauncher.getWorkspace();
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
index 00291a3..f4b4a91 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromTaskbarQsb.java
@@ -50,4 +50,9 @@
     protected void verifyVisibleContainerOnDismiss() {
         mLauncher.getLaunchedAppState().assertTaskbarVisible();
     }
+
+    @Override
+    protected void tapOutside(boolean tapRight, UiObject2 allAppsBottomSheet) {
+        mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java b/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
index e1b73a4..6d2631f 100644
--- a/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
+++ b/tests/tapl/com/android/launcher3/tapl/SelectModeButtons.java
@@ -16,19 +16,29 @@
 
 package com.android.launcher3.tapl;
 
+import static android.view.KeyEvent.KEYCODE_ESCAPE;
+
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
+
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.UiObject2;
 
+import com.android.launcher3.testing.shared.TestProtocol;
+
+import java.util.regex.Pattern;
+
 /**
  * View containing select mode buttons
  */
 public class SelectModeButtons {
     private final UiObject2 mSelectModeButtons;
     private final LauncherInstrumentation mLauncher;
+    private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
+            "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
 
-    SelectModeButtons(UiObject2 selectModeButtons,
-            LauncherInstrumentation launcherInstrumentation) {
-        mSelectModeButtons = selectModeButtons;
+
+    SelectModeButtons(LauncherInstrumentation launcherInstrumentation) {
+        mSelectModeButtons = launcherInstrumentation.waitForLauncherObject("select_mode_buttons");
         mLauncher = launcherInstrumentation;
     }
 
@@ -48,4 +58,24 @@
             }
         }
     }
+
+    /**
+     * Close select mode when ESC key is pressed.
+     * @return The Overview
+     */
+    @NonNull
+    public Overview dismissByEscKey() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
+            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ALT_ESC_UP);
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_ESCAPE),
+                    OVERVIEW_STATE_ORDINAL,
+                    "pressing Esc");
+            try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                    "pressed esc key")) {
+                return new Overview(mLauncher);
+            }
+        }
+    }
+
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index a202c53..e6315f3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -153,7 +153,7 @@
         return By.clazz(TextView.class).text("");
     }
 
-    private Rect getVisibleBounds() {
+    public Rect getVisibleBounds() {
         return mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID).getVisibleBounds();
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
index 064f80c..d05c112 100644
--- a/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAppIcon.java
@@ -68,6 +68,7 @@
 
     @Override
     protected boolean launcherStopsAfterLaunch() {
+        // false because if taskbar is showing then launcher is already stopped.
         return false;
     }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java b/tests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
index ec1cbd8..3895302 100644
--- a/tests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
+++ b/tests/tapl/com/android/launcher3/tapl/WidgetResizeFrame.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.tapl;
 
 import static com.android.launcher3.tapl.Launchable.DEFAULT_DRAG_STEPS;
+
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Point;
@@ -56,16 +57,20 @@
             Rect originalWidgetSize = widget.getVisibleBounds();
             Point targetStart = bottomResizeHandle.getVisibleCenter();
             Point targetDest = bottomResizeHandle.getVisibleCenter();
-            targetDest.offset(0, originalWidgetSize.height());
+            targetDest.offset(0,
+                    originalWidgetSize.height() + mLauncher.getCellLayoutBoarderHeight());
 
             final long downTime = SystemClock.uptimeMillis();
             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetStart,
                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            mLauncher.movePointer(targetStart, targetDest, DEFAULT_DRAG_STEPS,
-                    true, downTime, downTime, true,
-                    LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, targetDest,
-                    LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+            try {
+                mLauncher.movePointer(targetStart, targetDest, DEFAULT_DRAG_STEPS,
+                        true, downTime, downTime, true,
+                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+            } finally {
+                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, targetDest,
+                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+            }
 
             try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
                          "want to return resized widget resize frame")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index 105bc3b..6387b05 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 import static com.android.launcher3.tapl.LauncherInstrumentation.log;
 
+import android.annotation.Nullable;
 import android.graphics.Rect;
 
 import androidx.test.uiautomator.By;
@@ -114,7 +115,13 @@
                 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    /** Get widget with supplied text. */
     public Widget getWidget(String labelText) {
+        return getWidget(labelText, null);
+    }
+
+    /** Get widget with supplied text and app package */
+    public Widget getWidget(String labelText, @Nullable String testAppWidgetPackage) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "getting widget " + labelText + " in widgets list")) {
@@ -124,7 +131,8 @@
             mLauncher.assertTrue("Widgets container didn't become scrollable",
                     fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
 
-            final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer();
+            final UiObject2 widgetsContainer =
+                    findTestAppWidgetsTableContainer(testAppWidgetPackage);
             mLauncher.assertTrue("Can't locate widgets list for the test app: "
                             + mLauncher.getLauncherPackageName(),
                     widgetsContainer != null);
@@ -180,14 +188,22 @@
         return searchBar;
     }
 
-    /** Finds the widgets list of this test app from the collapsed full widgets picker. */
-    private UiObject2 findTestAppWidgetsTableContainer() {
+    /**
+     * Finds the widgets list of this test app or supplied test app package from the collapsed full
+     * widgets picker.
+     */
+    private UiObject2 findTestAppWidgetsTableContainer(@Nullable String testAppWidgetPackage) {
         final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
                 "widgets_list_header");
         final BySelector widgetPickerSelector = By.res(mLauncher.getLauncherPackageName(),
                 "container");
-        final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
-                mLauncher.getContext().getPackageName());
+
+        String packageName =  mLauncher.getContext().getPackageName();
+        final BySelector targetAppSelector = By
+                .clazz("android.widget.TextView")
+                .text((testAppWidgetPackage == null || testAppWidgetPackage.isEmpty())
+                                ? packageName
+                                : testAppWidgetPackage);
         final BySelector widgetsContainerSelector = By.res(mLauncher.getLauncherPackageName(),
                 "widgets_table");
 
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index f8fa00c..4fa93ef 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -17,10 +17,16 @@
 package com.android.launcher3.tapl;
 
 import static android.view.KeyEvent.KEYCODE_META_RIGHT;
+import static android.view.KeyEvent.KEYCODE_RECENT_APPS;
+import static android.view.KeyEvent.KEYCODE_TAB;
+import static android.view.KeyEvent.META_META_ON;
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED;
 
 import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT;
 
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
@@ -28,6 +34,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
@@ -59,10 +66,6 @@
     private static final String DROP_BAR_RES_ID = "drop_target_bar";
     private static final String DELETE_TARGET_TEXT_ID = "delete_target_text";
     private static final String UNINSTALL_TARGET_TEXT_ID = "uninstall_target_text";
-
-    static final Pattern EVENT_CTRL_W_DOWN = Pattern.compile(
-            "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_W"
-                    + ".*?metaState=META_CTRL_ON");
     static final Pattern EVENT_CTRL_W_UP = Pattern.compile(
             "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_W"
                     + ".*?metaState=META_CTRL_ON");
@@ -121,7 +124,10 @@
              LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to open all apps search")) {
             verifyActiveContainer();
-            mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT);
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_META_RIGHT),
+                    ALL_APPS_STATE_ORDINAL,
+                    "pressing keyboard shortcut");
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "pressed meta key")) {
                 return new HomeAllApps(mLauncher);
@@ -129,6 +135,40 @@
         }
     }
 
+    /** Opens the Launcher Overview page with the action+tab keyboard shortcut. */
+    public Overview openOverviewFromActionPlusTabKeyboardShortcut() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to open overview")) {
+            verifyActiveContainer();
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_TAB, META_META_ON),
+                    OVERVIEW_STATE_ORDINAL,
+                    "pressing keyboard shortcut");
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "pressed meta+tab key")) {
+                return new Overview(mLauncher);
+            }
+        }
+    }
+
+    /** Opens the Launcher Overview page with the Recents keyboard shortcut. */
+    public Overview openOverviewFromRecentsKeyboardShortcut() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to open overview")) {
+            verifyActiveContainer();
+            mLauncher.runToState(
+                    () -> mLauncher.getDevice().pressKeyCode(KEYCODE_RECENT_APPS),
+                    OVERVIEW_STATE_ORDINAL,
+                    "pressing keyboard shortcut");
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "pressed recents apps key")) {
+                return new Overview(mLauncher);
+            }
+        }
+    }
+
     /**
      * Returns the home qsb.
      *
@@ -192,16 +232,24 @@
     }
 
     /**
-     * Ensures that workspace is scrollable. If it's not, drags an icon icons from hotseat to the
-     * second screen.
+     * Ensures that workspace is scrollable. If it's not, drags a chrome app icon from hotseat
+     * to the second screen.
      */
     public void ensureWorkspaceIsScrollable() {
+        ensureWorkspaceIsScrollable("Chrome");
+    }
+
+    /**
+     * Ensures that workspace is scrollable. If it's not, drags an icon of a given app name from
+     * hotseat to the second screen.
+     */
+    public void ensureWorkspaceIsScrollable(String appName) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             final UiObject2 workspace = verifyActiveContainer();
             if (!isWorkspaceScrollable(workspace)) {
                 try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                         "dragging icon to a second page of workspace to make it scrollable")) {
-                    dragIcon(workspace, getHotseatAppIcon("Chrome"), pagesPerScreen());
+                    dragIcon(workspace, getHotseatAppIcon(appName), pagesPerScreen());
                     verifyActiveContainer();
                 }
             }
@@ -299,13 +347,23 @@
      */
     public Map<String, Point> getWorkspaceIconsPositions() {
         final UiObject2 workspace = verifyActiveContainer();
+        mLauncher.waitForLauncherInitialized(); // b/319501259
         List<UiObject2> workspaceIcons =
                 mLauncher.waitForObjectsInContainer(workspace, AppIcon.getAnyAppIconSelector());
         return workspaceIcons.stream()
                 .collect(
                         Collectors.toMap(
-                                /* keyMapper= */ UiObject2::getText,
-                                /* valueMapper= */ UiObject2::getVisibleCenter,
+                                /* keyMapper= */ uiObject21 -> {
+                                    Log.d(UIOBJECT_STALE_ELEMENT, "keyText: " +
+                                            uiObject21.getText());
+                                    return uiObject21.getText();
+                                },
+                                /* valueMapper= */ uiObject2 -> {
+                                    Log.d(UIOBJECT_STALE_ELEMENT, uiObject2.getText() +
+                                            " dispId" + uiObject2.getDisplayId() +
+                                            " parent" + uiObject2.getParent());
+                                    return uiObject2.getVisibleCenter();
+                                },
                                 /* mergeFunction= */ (p1, p2) -> p1.x < p2.x ? p1 : p2));
     }
 
@@ -450,7 +508,12 @@
     }
 
     /** Returns the index of the current page */
-    private static int geCurrentPage(LauncherInstrumentation launcher) {
+    public int getCurrentPage() {
+        return getCurrentPage(mLauncher);
+    }
+
+    /** Returns the index of the current page */
+    private static int getCurrentPage(LauncherInstrumentation launcher) {
         return launcher.getTestInfo(TestProtocol.REQUEST_WORKSPACE_CURRENT_PAGE_INDEX).getInt(
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
@@ -524,7 +587,8 @@
      * This function expects the launchable is inside the workspace and there is no drop event.
      */
     static void dragIconToWorkspace(
-            LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> destSupplier) {
+            LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> destSupplier,
+            boolean isDraggingToFolder) {
         dragIconToWorkspace(
                 launcher,
                 launchable,
@@ -532,7 +596,8 @@
                 /* isDecelerating= */ false,
                 () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
                 /* expectDropEvents= */ null,
-                /* startsActivity = */ false);
+                /* startsActivity = */ false,
+                isDraggingToFolder);
     }
 
     static void dragIconToWorkspace(
@@ -543,7 +608,8 @@
             @Nullable Runnable expectDropEvents,
             boolean startsActivity) {
         dragIconToWorkspace(launcher, launchable, dest, /* isDecelerating */ true,
-                expectLongClickEvents, expectDropEvents, startsActivity);
+                expectLongClickEvents, expectDropEvents, startsActivity,
+                /* isDraggingToFolder */ false);
     }
 
     static void dragIconToWorkspace(
@@ -553,10 +619,13 @@
             boolean isDecelerating,
             Runnable expectLongClickEvents,
             @Nullable Runnable expectDropEvents,
-            boolean startsActivity) {
+            boolean startsActivity,
+            boolean isDraggingToFolder) {
         try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
                 "want to drag icon to workspace")) {
             final long downTime = SystemClock.uptimeMillis();
+            Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                    "Workspace.dragIconToWorkspace: starting drag | downtime: " + downTime);
             Point dragStart = launchable.startDrag(
                     downTime,
                     expectLongClickEvents,
@@ -580,11 +649,27 @@
                 dragStart = screenEdge;
             }
 
-            // targetDest.x is now between 0 and displayX so we found the target page,
-            // we just have to put move the icon to the destination and drop it
-            launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
-                    downTime, SystemClock.uptimeMillis(), false,
-                    LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+            // targetDest.x is now between 0 and displayX so we found the target page.
+            // If not a folder, we just have to put move the icon to the destination and drop it.
+            // If it's a folder we want to drag to the folder icon and then drag to the center of
+            // that folder when it opens.
+            if (isDraggingToFolder) {
+                Point finalDragStart = dragStart;
+                Point finalTargetDest = targetDest;
+                Folder folder = executeAndWaitForFolderOpen(launcher, () -> launcher.movePointer(
+                        finalDragStart, finalTargetDest, DEFAULT_DRAG_STEPS, isDecelerating,
+                        downTime, SystemClock.uptimeMillis(), false,
+                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER));
+
+                Rect dropBounds = folder.getDropLocationBounds();
+                dragStart = targetDest;
+                targetDest = new Point(dropBounds.centerX(), dropBounds.centerY());
+            }
+
+            launcher.movePointer(dragStart, targetDest,
+                    DEFAULT_DRAG_STEPS, isDecelerating, downTime, SystemClock.uptimeMillis(),
+                    false, LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+
             dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents, startsActivity);
         }
     }
@@ -637,7 +722,7 @@
             Point currentPosition, int destinationWorkspaceIndex, int y) {
         final long downTime = SystemClock.uptimeMillis();
         int displayX = launcher.getRealDisplaySize().x;
-        int currentPage = Workspace.geCurrentPage(launcher);
+        int currentPage = Workspace.getCurrentPage(launcher);
         int counter = 0;
         while (currentPage != destinationWorkspaceIndex) {
             counter++;
@@ -656,7 +741,7 @@
                     () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
                             true, downTime, downTime, true,
                             LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER));
-            currentPage = Workspace.geCurrentPage(launcher);
+            currentPage = Workspace.getCurrentPage(launcher);
             currentPosition = screenEdge;
         }
         return currentPosition;
@@ -669,6 +754,16 @@
                 () -> "Page scroll didn't happen", "Scrolling page");
     }
 
+    private static Folder executeAndWaitForFolderOpen(LauncherInstrumentation launcher,
+            Runnable command) {
+        launcher.executeAndWaitForEvent(command,
+                event -> TestProtocol.FOLDER_OPENED_MESSAGE.equals(
+                        event.getClassName().toString()),
+                () -> "Fail to open folder.",
+                "open folder");
+        return new Folder(launcher);
+    }
+
     static void dragIconToHotseat(
             LauncherInstrumentation launcher,
             Launchable launchable,
@@ -695,10 +790,9 @@
      */
     public void flingForward() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            final UiObject2 workspace = verifyActiveContainer();
-            mLauncher.scroll(workspace, Direction.RIGHT,
-                    new Rect(0, 0, mLauncher.getEdgeSensitivityWidth() + 1, 0),
-                    FLING_STEPS, false);
+            Rect workspaceBounds = mLauncher.getVisibleBounds(verifyActiveContainer());
+            mLauncher.pointerScroll(
+                    workspaceBounds.centerX(), workspaceBounds.centerY(), Direction.RIGHT);
             verifyActiveContainer();
         }
     }
@@ -709,10 +803,9 @@
      */
     public void flingBackward() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
-            final UiObject2 workspace = verifyActiveContainer();
-            mLauncher.scroll(workspace, Direction.LEFT,
-                    new Rect(mLauncher.getEdgeSensitivityWidth() + 1, 0, 0, 0),
-                    FLING_STEPS, false);
+            Rect workspaceBounds = mLauncher.getVisibleBounds(verifyActiveContainer());
+            mLauncher.pointerScroll(
+                    workspaceBounds.centerX(), workspaceBounds.centerY(), Direction.LEFT);
             verifyActiveContainer();
         }
     }
@@ -726,7 +819,6 @@
     public Widgets openAllWidgets() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             verifyActiveContainer();
-            mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_CTRL_W_DOWN);
             mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_CTRL_W_UP);
             mLauncher.getDevice().pressKeyCode(KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON);
             try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer("pressed Ctrl+W")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index e5a2a2e..b42d43b 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -15,7 +15,10 @@
  */
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
+
 import android.graphics.Point;
+import android.util.Log;
 
 import java.util.function.Supplier;
 
@@ -76,6 +79,9 @@
              LauncherInstrumentation.Closable c = launcher.addContextLayer(
                      String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))) {
             final Supplier<Point> dest = () -> Workspace.getCellCenter(launcher, cellX, cellY);
+            Log.d(TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE,
+                    "WorkspaceDragSource.dragToWorkspace: dragging icon to workspace | dest: "
+                            + dest.get());
             Workspace.dragIconToWorkspace(
                     launcher,
                     launchable,